[Solved]My model is rendered one half from the front and the other half from the back

Started by
12 comments, last by Nik02 14 years, 3 months ago
Hi i made a human face and when i render it i saw one half of the face from the front and the other half from the back, here is a capture changing from z to -z the eye vector: http://img696.imageshack.us/g/57765909.png/ [Edited by - jor1980 on December 28, 2009 5:09:32 PM]
Advertisement
Are the normals on half the head reversed? Possibly during mirroring?
Quote:Original post by Deranged
Are the normals on half the head reversed? Possibly during mirroring?


In my FVF i didn´t use normals, here i leave you the code to you to see if there are something wrong.





Imports Microsoft.DirectX.Direct3D
Imports Microsoft.DirectX


Public Class Form1
Private device As Device
Dim verticest As CustomVertex.PositionTextured() = New CustomVertex.PositionTextured(1398) {}
Dim indices As Short() = New Short(7991) {}




Public Sub Initialize()
Dim Present As PresentParameters = New PresentParameters
Present.Windowed = True
Present.SwapEffect = SwapEffect.Discard
device = New Device(0, DeviceType.Hardware, Me.Handle, CreateFlags.SoftwareVertexProcessing, Present)
device.RenderState.Lighting = False

End Sub


Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Me.Text = "DirectX Tutorial using Visual Basic"
Me.Setstyle(Controlstyles.AllPaintingInWmPaint Or Controlstyles.Opaque, True)
Initialize()


Dim nºarchivo As Integer = FreeFile()

FileOpen(nºarchivo, My.Computer.FileSystem.SpecialDirectories.Desktop & "\cara.3d", OpenMode.Input)



For i = 0 To 1398
Dim dato As String
dato = LineInput(nºarchivo)
Dim Datoparts As String()
Datoparts = Split(dato, " ")

verticest(i).SetPosition(New Vector3(NumerosDecimales(Datoparts(0)), NumerosDecimales(Datoparts(1)), NumerosDecimales(Datoparts(2))))

verticest(i).Tu = (NumerosDecimales(Datoparts(3)))
verticest(i).Tv = 1 - (NumerosDecimales(Datoparts(4)))


Next

For i = 0 To 2663
Dim dato As String
dato = LineInput(nºarchivo)
Dim Datoparts As String()
Datoparts = Split(dato, " ")
indices(3 * i) = Datoparts(0)
indices((3 * i) + 1) = Datoparts(1)
indices((3 * i) + 2) = Datoparts(2)
Next

End Sub

Private Sub Form1_OnPaint(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Me.Paint
device.RenderState.CullMode = Cull.None
device.RenderState.FillMode = FillMode.Solid

device.Clear(ClearFlags.Target, Color.Black, 1, 0)


Dim imagen As New Bitmap("C:\Users\Jorge\Desktop\fernando.png")

Dim textura As New Texture(device, imagen, Usage.Dynamic, Pool.Default)
device.MultiplyTransform(TransformType.Projection, Matrix.PerspectiveFovLH(Math.PI / 4, _
Me.Width / Me.Height, 1, 100))





device.MultiplyTransform(TransformType.World, Matrix.LookAtLH(New Vector3(0, 0, -8), New Vector3(0, 2, 0), New Vector3(0, 1, 0)))




device.BeginScene()

device.SetTexture(0, textura)
device.VertexFormat = CustomVertex.PositionTextured.Format
device.DrawIndexedUserPrimitives(PrimitiveType.TriangleList, 0, 1399, 2664, indices, True, verticest)

device.EndScene()
device.Present()

End Sub
I don't know if it is enabled by default, but is depth test enabled?
Quote:Original post by fcoelho
I don't know if it is enabled by default, but is depth test enabled?


All i did is in the previous code, i don´t know how to solve this
Even if you don't use per-vertex normals (as in lighting), the hardware still calculates face normals for your triangles for the purpose of backface culling.

When you have mirrored your geometry, the winding order (counterwise or counterclockwise vertices) of the triangles has mirrored accordingly and thus their geometric normal points in the opposite direction from what you'd expect.

As a quick fix, try disabling backface culling. The long-term fix is to fix your model so that the winding order of your triangles is consistent.

Most modeling programs automatically correct the winding order for you when you use a "mirror modifier" (exact name varies). Either your program doesn't, or you used some kind of negative scaling modeling technique that didn't capture the intent of the modification (for example, mirroring only vertex positions).

Niko Suni

As a separate note, it is a very bad practice to hard-code stuff like the number of indices and vertices. Instead, determine such values from the model file. This way, when the file changes, your code will not break. There are other problems with your code structure as well, but I don't iterate them here unless you want me to.

Also, Managed DX is effectively dead. I recommend using SlimDX to replace it, seeing as you use VB.

Niko Suni

Quote:Original post by Nik02
As a separate note, it is a very bad practice to hard-code stuff like the number of indices and vertices. Instead, determine such values from the model file. This way, when the file changes, your code will not break. There are other problems with your code structure as well, but I don't iterate them here unless you want me to.

Also, Managed DX is effectively dead. I recommend using SlimDX to replace it, seeing as you use VB.


Of course you can tell me all my faults, i want to learn and thats the way.The reason i use managed directx is because slimdx seems to be a little bit diferent froma managed directx, and i tried to make the same program on slimdx and i can´t see anything in the screen
I'll get back to you about the code tomorrow, as I need to sleep for a while now [smile]

In the meanwhile, apply my quick fix by setting the cull render state to "none".

Also, fcoelho was correct in that you don't use depth buffering. For anything but the most simple of meshes you do want to use it. It can be enabled by setting the AutoDepthStencil and DepthStencilFormat fields of your present parameters structure to appropriate values. If you do enable it, be sure to clear the depth buffer in addition to the ordinary color buffer when you call Clear.

You shouldn't give up on SlimDX so easily. While the syntax is a bit different than MDX (as SlimDX is closely modeled after native DX), the underlying concepts of drawing stuff to the screen are exactly same. And if you do your coding with the DX debug systems running, you can get very accurate info as to why something doesn't work.

Also, there's no guarantee that MDX still works on newer versions of Windows. I haven't tested it on "7" but I wouldn't be surprised if it ceased to initialize out of the box.

Niko Suni

Okay, here's my analysis of your code in general, and recommendations on how to fix the flaws. I don't drill very deep on the issues; for that, I recommend reading relevant articles from MSDN.

If I sound harsh here, it is unintentional. My goal in this post is to help you.


VB usage/coding style:

-You have defined all the functionality in one module, Form1. To reap the benefits of the object-oriented paradigm, you should divide your functionality into classes - for example, a Mesh class which has member functions Load(fileName as String, parentDevice as Direct3D.Device), Render() etc. (for example). This way, you don't have to search thru a lot of irrelevant code everytime you change something. This approach has a lot of other benefits too, but listing them would require a whole book.

-FreeFile and FileOpen are deprecated functions, they are only provided for backwards compatibility with older versions of Visual Basic. Consider using the stream classes to do your file handling - in addition to reading actual disk files, you can use network or memory streams instead for no additional work. Also, the stream classes have additional functionality such as asynchronous processing.

-You don't do any error checking whatsoever. You should check that a file open operation succeeded before reading data off it, and that a D3D device was successfully initialized before you send requests to it. If something goes wrong, your code will crash as it is. With proper error handling, you can gracefully handle the exception conditions. A D3D device can be especially crash-prone and cause blue screens upon exceptions, since it is only a relatively thin layer between your program and the hardware.



D3D usage:

-Usually, rendering is done on the idle time of the application instead of the OnPaint handler - that is, everytime the app's Windows message queue is empty, render. Google for "d3d message pump vb" for a proper implementation. Of course, if it is enough to paint the screen less often (such as in a chess game, for example), OnPaint can be fast enough.

-You don't seem to call Device.SetTransform anywhere in the code. MultiplyTransform multiplies the previous transform of the device with the new transform you provide, so the effect will be cumulative. This is usually not what you want. In your case, I could imagine that the side effects of MultiplyTransform cause your model to zoom away from the screen everytime you render, since you multiply the view and projection matrices by their previous values.

-Consider using vertex and index buffers to feed your geometry to the hardware. User primitives are not optimal since the device cannot allocate them statically for best performance, and you will upload the geometry every time you call the drawing function.

-You should release all device resources upon exiting your app. Otherwise, your app can cause memory leaks as the system cannot determine which objects it can unload from memory and/or release physical device resources from.

-Use the D3D debug runtime when developing apps. Seriously. If you don't know how, read up on MSDN. It is time well spent.



General best practices:

-You are re-loading and re-creating your texture every single frame. This destroys your performance, and it can't be good for your hard drive either in the long run.

-As I said previously, it is a bad practice to hard-code any values to your files. In your case, the number of vertices and indices should be read from the model file itself. Also, you should store material settings (and other related stuff) or at least references to them in the model file. From your code, I can deduce that the file format is too simple for this kind of robust handling, so consider defining a file format that can store all the data, or use a well-known file format. Obj format is pretty close to your current format.

-Don't hardcode file paths. Even though SpecialDirectories.Desktop is technically not a hard-coded path, wouldn't it make more sense to store your resources relative to the executable path?

-In general, in my opinion VB isn't the greatest language for game development. However, the priority should be in getting stuff done. If you know the language well, do keep using it but consider learning C-style languages as well. Native D3D development is done in C++, and it is the thinnest possible interface between your app and D3D.



Consider this list as a summary, not a comprehensive list of all possible issues.

I hope this helps!

Niko Suni

This topic is closed to new replies.

Advertisement