Basic render 3D perspective projection onto 2D screen with camera (without opengl)

后端 未结 8 986
南方客
南方客 2020-12-04 10:21

Let\'s say I have a data structure like the following:

Camera {
   double x, y, z

   /** ideally the camera angle is positioned to aim at the 0,0,0 point */         


        
相关标签:
8条回答
  • 2020-12-04 10:29

    Run it thru a ray tracer:

    Ray Tracer in C# - Some of the objects he has will look familiar to you ;-)

    And just for kicks a LINQ version.

    I'm not sure what the greater purpose of your app is (you should tell us, it might spark better ideas), but while it is clear that projection and ray tracing are different problem sets, they have a ton of overlap.

    If your app is just trying to draw the entire scene, this would be great.

    Solving problem #1: Obscured points won't be projected.
    Solution: Though I didn't see anything about opacity or transparency on the blog page, you could probably add these properties and code to process one ray that bounced off (as normal) and one that continued on (for the 'transparency').

    Solving problem #2: Projecting a single pixel will require a costly full-image tracing of all pixels.
    Obviously if you just want to draw the objects, use the ray tracer for what it's for! But if you want to look up thousands of pixels in the image, from random parts of random objects (why?), doing a full ray-trace for each request would be a huge performance dog.

    Fortunately, with more tweaking of his code, you might be able to do one ray-tracing up front (with transparancy), and cache the results until the objects change.

    If you're not familiar to ray tracing, read the blog entry - I think it explains how things really work backwards from each 2D pixel, to the objects, then the lights, which determines the pixel value.

    You can add code so as intersections with objects are made, you are building lists indexed by intersected points of the objects, with the item being the current 2d pixel being traced.

    Then when you want to project a point, go to that object's list, find the nearest point to the one you want to project, and look up the 2d pixel you care about. The math would be far more minimal than the equations in your articles. Unfortunately, using for example a dictionary of your object+point structure mapping to 2d pixels, I am not sure how to find the closest point on an object without running through the entire list of mapped points. Although that wouldn't be the slowest thing in the world and you could probably figure it out, I just don't have the time to think about it. Anyone?

    good luck!

    "Also, I don't understand in the wiki entry what is the viewer's position vers the camera position" ... I'm 99% sure this is the same thing.

    0 讨论(0)
  • 2020-12-04 10:30

    Following the wikipedia, first calculate "d":

    http://upload.wikimedia.org/wikipedia/en/math/6/0/b/60b64ec331ba2493a2b93e8829e864b6.png

    In order to do this, build up those matrices in your code. The mappings from your examples to their variables:

    θ = Camera.angle*

    a = SomePointIn3DSpace

    c = Camera.x | y | z

    Or, just do the equations separately without using matrices, your choice:

    http://upload.wikimedia.org/wikipedia/en/math/1/c/8/1c89722619b756d05adb4ea38ee6f62b.png

    Now we calculate "b", a 2D point:

    http://upload.wikimedia.org/wikipedia/en/math/2/5/6/256a0e12b8e6cc7cd71fa9495c0c3668.png

    In this case ex and ey are the viewer's position, I believe in most graphics systems half the screen size (0.5) is used to make (0, 0) the center of the screen by default, but you could use any value (play around). ez is where the field of view comes into play. That's the one thing you were missing. Choose a fov angle and calculate ez as:

    ez = 1 / tan(fov / 2)

    Finally, to get bx and by to actual pixels, you have to scale by a factor related to the screen size. For example, if b maps from (0, 0) to (1, 1) you could just scale x by 1920 and y by 1080 for a 1920 x 1080 display. That way any screen size will show the same thing. There are of course many other factors involved in an actual 3D graphics system but this is the basic version.

    0 讨论(0)
  • 2020-12-04 10:31

    You want to transform your scene with a matrix similar to OpenGL's gluLookAt and then calculate the projection using a projection matrix similar to OpenGL's gluPerspective.

    You could try to just calculate the matrices and do the multiplication in software.

    0 讨论(0)
  • 2020-12-04 10:39

    Converting points in 3D-space into a 2D point on a screen is simply made by using a matrix. Use a matrix to calculate the screen position of your point, this saves you a lot of work.

    When working with cameras you should consider using a look-at-matrix and multiply the look at matrix with your projection matrix.

    0 讨论(0)
  • 2020-12-04 10:43

    You might be interested in just seeing how GLUT does it behind the scenes. All of these methods have similar documentation that shows the math that goes into them.

    The three first lectures from UCSD might be very helful, and contain several illustrations on this topic, which as far as I can see is what you are really after.

    0 讨论(0)
  • 2020-12-04 10:46

    Assuming the camera is at (0, 0, 0) and pointed straight ahead, the equations would be:

    ScreenData.x = SomePointIn3DSpace.x / SomePointIn3DSpace.z * constant;
    ScreenData.y = SomePointIn3DSpace.y / SomePointIn3DSpace.z * constant;
    

    where "constant" is some positive value. Setting it to the screen width in pixels usually gives good results. If you set it higher then the scene will look more "zoomed-in", and vice-versa.

    If you want the camera to be at a different position or angle, then you will need to move and rotate the scene so that the camera is at (0, 0, 0) and pointed straight ahead, and then you can use the equations above.

    You are basically computing the point of intersection between a line that goes through the camera and the 3D point, and a vertical plane that is floating a little bit in front of the camera.

    0 讨论(0)
提交回复
热议问题