Sign in to follow this  
Son of Makuta

DirectX 9 complete lack of 3D rendering

Recommended Posts

I've been stuck on this for three days now, and so I turn to the Internet for help. I'm trying to write a game (aren't we all?) and I'm currently just beginning the 3D rendering system. I'm trying to make it render a tetrahedron in fetching blue. The problem I have is that nothing at all shows up.

I've compared my code to the GameTutorials examples and source code from the book I'm using to no avail; I don't appear to have missed anything out. The font class renders just fine, but as for anything else, I just get a black screen. I'll put down some excerpts of my code in a moment, but for now here's a list of things I've tried/checked:

- Tried multiple camera orientations, moving the camera around, increasing FOV, and eventually wrapping the tetrahedron around it. Nothing. I can assume the tetrahedron isn't simply out of position. All faces are being specified in a clockwise direction. Lighting and fog are switched off.
- World transformation is the identity. View transformation is being set each frame to the camera's view matrix (I've tried setting this with D3DXMatrixLookAtLH as well as by inverting the world matrix as is currently the case. Neither worked). Perspective transformation is set when the engine loads. Vertex and index buffers are both being filled correctly (I have a bit of code that outputs them to a log file, which I'll print below). I tried using just the vertex buffer, and then an array of vertices and no buffers at all. Neither of those worked.
- Tried various colours, enabling/disabling alpha blending, different-colour backgrounds. I can assume that the tetrahedron isn't transparent or otherwise invisible.
- Removing the text. I can assume that the text isn't in some way obscuring the tetrahedron and setting up the fonts doesn't do anything weird to the rendering settings.
- Changing the vertex type in use from D3DFVF_XYZRHW | D3DFVF_DIFFUSE (4-vector for position, diffuse colour) to D3DFVF_XYZ | D3DFVF_DIFFUSE (3-vector position, colour). That didn't work either, so I changed it back. The vertex is meant to have a flat colour, no lighting, and no texture. The fonts use a vertex struct with a 4-vector for position, a colour, and a texture, and they work fine.

Does anyone have any ideas? Nothing I've tried has provoked any sort of result whatsoever - I've not seen a single polygon, whether in position or not. The 3D rendering is being called right before the font rendering; the screen isn't being cleared before the End() call or anything like that.

I've included some relevant excerpts from the code below.

Engine.cpp: loading procedure (constructor) and Run() (game loop)


//Constructor: Engine doesn't have a separate load function, instead being loaded as soon as it is created.
//This is because, since the engine only needs to be loaded once, we might as well.
//It ensures the game can't possibly be set up without loading the engine, although I'm sure adding g_engine->Load(); wouldn't kill anyone.
Engine::Engine(EngineSetup* setup)
{
//Indicate that the engine is not yet loaded.
m_loaded = false;

//First create the logfile, so I can moan about stuff that goes wrong in the rest of the function.
g_log = new LogOutput();

//Tell people that it worked.
g_log->out("Loading initialised");

//If no setup structure was passed in, then use a default one.
//Otherwise, make a copy of the passed-in structure.
m_setup = new EngineSetup;
if(setup != NULL)
memcpy(m_setup, setup, sizeof(EngineSetup));

//Store a pointer to the engine in a global variable for easy access.
g_engine = this;

g_log->out("Engine setup registered");

//Prepare and register the window class.
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_CLASSDC;
wcex.lpfnWndProc = WindowProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = m_setup->instance;
wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = NULL;
wcex.lpszMenuName = NULL;
wcex.lpszClassName = "WindowClass";
wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
RegisterClassEx(&wcex);

g_log->out("WNDCLASSEX registered");

//Initialise the COM using multithreaded concurrency.
CoInitializeEx(NULL, COINIT_MULTITHREADED);
g_log->out("COM initialised");

//Create the Direct3D interface.
IDirect3D9* d3d = Direct3DCreate9(D3D_SDK_VERSION);
if (!d3d) {
g_log->out("D3D creation failed");
return;
} else {
g_log->out("Direct3D interface created");
}

//Enumerate Direct3D device configurations on the default adapter.
g_deviceEnumeration = new DeviceEnumeration;
if(g_deviceEnumeration->Enumerate(d3d) != IDOK)
{
SAFE_RELEASE(d3d);
return;
}
g_log->out("D3D device configurations enumerated");

//Make the window purrdy
DWORD winStyleEx = WS_EX_CLIENTEDGE;
DWORD winStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME |
WS_CLIPCHILDREN | WS_CLIPSIBLINGS;

//Create the window and retrieve a handle to it.
m_window = CreateWindowEx(winStyleEx, "WindowClass", m_setup->name, winStyle, CW_USEDEFAULT, CW_USEDEFAULT,
g_deviceEnumeration->GetSelectedDisplayMode()->Width, g_deviceEnumeration->GetSelectedDisplayMode()->Height,
NULL, NULL, m_setup->instance, NULL);
g_log->out("Window created");

//Prepare the device presentation parameters.
D3DPRESENT_PARAMETERS d3dpp = {0};
d3dpp.BackBufferWidth = g_deviceEnumeration->GetSelectedDisplayMode()->Width;
d3dpp.BackBufferHeight = g_deviceEnumeration->GetSelectedDisplayMode()->Height;
d3dpp.BackBufferFormat = g_deviceEnumeration->GetSelectedDisplayMode()->Format;
d3dpp.BackBufferCount = m_setup->totalBackBuffers;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = m_window;
d3dpp.Windowed = g_deviceEnumeration->IsWindowed();
d3dpp.EnableAutoDepthStencil = true;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
d3dpp.FullScreen_RefreshRateInHz = g_deviceEnumeration->GetSelectedDisplayMode()->RefreshRate;
d3dpp.PresentationInterval = (g_deviceEnumeration->IsVSynced()) ? (D3DPRESENT_INTERVAL_DEFAULT) : (D3DPRESENT_INTERVAL_IMMEDIATE);

//Destroy the device enumeration object.
SAFE_DELETE(g_deviceEnumeration);
g_log->out("Parameters presented");

//Create the Direct3D device with hardware vertex processing.
if(FAILED(d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_window, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &m_device)))
{
//Create the Direct3D device with mixed vertex processing.
if(FAILED(d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_window, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &m_device)))
{
//Create the Direct3D device with software vertex processing.
if(FAILED(d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_window, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &m_device))) {
g_log->out("D3D device creation failed");
return;
}
else g_log->out("D3D device created with software vertex processing");
}
else g_log->out("D3D device created with mixed vertex processing");
}
else g_log->out("D3D device created with hardware vertex processing");

HRESULT resCheck = 0;

//Switch lighting off by default.
resCheck = m_device->SetRenderState(D3DRS_LIGHTING, false);
if (resCheck == D3D_OK) g_log->out("Lighting switched off");
else return;

//Alpha blending should be enabled.
g_engine->GetDevice()->SetRenderState(D3DRS_ALPHATESTENABLE, false);
if (resCheck == D3D_OK) g_log->out("Alpha-blending switched on");
else return;

//Let's pass on the fog of war.
g_engine->GetDevice()->SetRenderState(D3DRS_FOGENABLE, false);
if (resCheck == D3D_OK) g_log->out("Fog switched off");
else return;

//Enable Z-buffer
resCheck = m_device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
if (resCheck == D3D_OK) g_log->out("Z-buffer enabled");
else return;

//Set the texture filters.
//First get the device caps
D3DCAPS9 caps;
resCheck = d3d->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);
if (resCheck == D3D_OK) g_log->out("Device caps acquired");
else return;

//Loop through and set the mag/min filters for all the possible texture stages
for(unsigned int i = 0; i <caps.MaxTextureBlendStages; ++i)
{
//resCheck = m_device->SetSamplerState(i, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC);
resCheck = m_device->SetSamplerState(i, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
if (resCheck != D3D_OK) {
g_log->out("Magnification filter setting failure");
return;
}

//Set minification filter,
//resCheck = m_device->SetSamplerState(i, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC);
resCheck = m_device->SetSamplerState(i, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
if (resCheck != D3D_OK) {
g_log->out("Minification filter setting failure");
return;
}

//Enable mipmapping in general.
resCheck = m_device->SetSamplerState(i, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
if (resCheck != D3D_OK) {
g_log->out("Mipmap filter setting failure");
return;
}
}
g_log->out("Texture filtering configured");

//Set the projection matrix.
D3DXMatrixPerspectiveFovLH(&m_projection, D3DX_PI / 2, (float)d3dpp.BackBufferWidth / (float)d3dpp.BackBufferHeight, 0.01f / m_setup->scale, 2000.0f / m_setup->scale);
resCheck = m_device->SetTransform(D3DTS_PROJECTION, &m_projection);
if (resCheck == D3D_OK) g_log->out("Projection matrix configured");
else return;

//Store the display mode details and start the swap chain on the first backbuffer.
m_displayMode.Width = d3dpp.BackBufferWidth;
m_displayMode.Height = d3dpp.BackBufferHeight;
m_displayMode.RefreshRate = d3dpp.FullScreen_RefreshRateInHz;
m_displayMode.Format = d3dpp.BackBufferFormat;
m_currentBackBuffer = 0;
g_log->out("Display mode configured");

//Create the sprite interface.
resCheck = D3DXCreateSprite(m_device, &m_sprite);
if (resCheck == D3D_OK) g_log->out("Sprite created");
else return;

//Create the vector of states.
m_states = new vector<State*>;
m_currentState = NULL;
g_log->out("State list created");

//Create the resource managers.
m_scriptManager = new ResourceManager<Script>;
g_log->out("Resource managers created");

//Create the interpreters.
g_vi = new VariableInterpreter();
g_log->out("Interpreters created");

//Create the input object.
m_input = new Input(m_window);
g_log->out("Input object created");

//Seed the random number generator with the current time.
srand(GetTickCount());

//Initialise the rendering manager.
g_renderManager = new RenderingManager();
g_log->out("Rendering manager created");

//Allow the application to perform any state setup now.
if(m_setup->StateSetup != NULL)
m_setup->StateSetup();
g_log->out("States set up");

//Release the Direct3D interface as it is no longer needed.
SAFE_RELEASE(d3d);
g_log->out("D3D released");

//ARRRRRE YOOOOUU REEAADDYYY TOOOO RUUUMMMBBBBLLLEEEEE
m_loaded = true;
g_log->out("Engine loading complete");
}


//Run: Enters the engine into the main processing loop.
//Run contains the game loop and terminates the program (by deleting the engine) as soon as this loop exits.
//The game loop also contains just-in-case code that allows Windows commands to take priority over whatever the game's doing, as is standard in Win32 applications.
void Engine::Run()
{
//Ensure the engine is loaded.
if(m_loaded == true)
{

//Show the window.
ShowWindow(m_window, SW_NORMAL);

//Used to retrieve details about the camera from the application.
CameraSetup camera;

//Enter the game loop, and the Dragon while you're at it.
MSG msg = {0};
while(msg.message != WM_QUIT)
{
//First see if Windows is demanding we do a thing.
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}

//If Windows doesn't have any pressing concerns, forge ahead with the game loop.
else if(!m_deactive)
{
//Calculate the elapsed time.
unsigned long currentTime = GetTickCount();
static unsigned long lastTime = currentTime; //Only assigns when the variable is first initialised
float elapsed = (currentTime - lastTime) / 1000.0f;
lastTime = currentTime;

//Update the input object, reading the keyboard and mouse.
m_input->Update();

//Check if the user wants to make a forced exit.
if(m_input->GetKeyPress(DIK_F1))
PostQuitMessage(0);

//Request the camera from the current state, if there is one.
if(m_currentState != NULL)
m_currentState->RequestCamera(&camera);

//Ensure the camera is valid, and set the view transformation if so.
if(camera.camera != NULL) {
m_device->SetTransform(D3DTS_VIEW, camera.camera->GetViewMatrix());
}

//Update the current state (if there is one), taking state changes into account.
m_stateChanged = false;
if(m_currentState != NULL)
m_currentState->Update(elapsed);
if(m_stateChanged == true)
continue;

//Begin the scene.
m_device->Clear(0, NULL, camera.viewClearFlags, 0, 1.0f, 0);
if(SUCCEEDED(m_device->BeginScene()))
{
//Render the scene, if there is a valid camera.
if(camera.camera != NULL)
g_renderManager->Render();

//Render the current state, if there is one.
if(m_currentState != NULL)
m_currentState->Render();

//End the scene and present it.
m_device->EndScene();
m_device->Present(NULL, NULL, NULL, NULL);

//Keep track of the index of the current back buffer.
if(++m_currentBackBuffer == m_setup->totalBackBuffers + 1)
m_currentBackBuffer = 0;
}
}
}
}

//The game loop has exited, so the game quits. Destroy the engine, which triggers the destructor, of course.
SAFE_DELETE(g_engine);
}





RenderingManager.cpp: CreateBuffers() and Render()
CreateBuffers() turns a pair of vectors, m_verts and m_inds, into a pair of vertex buffers. (At the moment, it also fills an array of 12 vertices, but that doesn't add a whole lot of extra code.) Render() does the obvious. I filled Render() with HRESULT checks, but none of them appear to be failing.


//CreateBuffers: This sets addMode to false, commits everything in the vectors to the buffers (creating said buffers in the process) and clears the vector of indices.
void RenderingManager::CreateBuffers()
{
addMode = false;

//OK, here we go...
unsigned int vSize = m_verts->size() * TL_VERTEX_FVF_SIZE;
unsigned int iSize = m_inds->size() * sizeof(unsigned int);
if (g_engine->GetDevice()->CreateVertexBuffer(vSize, 0, TL_VERTEX_FVF, D3DPOOL_MANAGED, &m_vbuffer, NULL) != D3D_OK) { g_log->out("CreateVertexBuffer failed"); }
if (g_engine->GetDevice()->CreateIndexBuffer(iSize, 0, D3DFMT_INDEX32, D3DPOOL_MANAGED, &m_ibuffer, NULL) != D3D_OK) { g_log->out("CreateIndexBuffer failed"); }

//Lock the buffers to prepare for writing.
TLVertex* vb = NULL;
unsigned int* ib = NULL;
if (m_vbuffer->Lock(0, vSize, (void**)&vb, 0) != D3D_OK) { g_log->out("Vertex buffer lock unsuccessful"); }
if (m_ibuffer->Lock(0, iSize, (void**)&ib, 0) != D3D_OK) { g_log->out("Index buffer lock unsuccessful"); }

//Copy over the data.
for (unsigned int i = 0; i < m_verts->size(); i++) { vb[i] = (*m_verts)[i]; }
for (unsigned int i = 0; i < m_inds->size(); i++) { ib[i] = (*m_inds)[i]; vertices[i] = (*m_verts)[(*m_inds)[i]]; }

//Testing
TLVertex v;
unsigned int u;
for (unsigned int i = 0; i < m_inds->size(); i++) {
u = ib[i];
v = vb[u];
g_log->out("Index " + sconv::MakeString((int)u) + " points to vertex (" + sconv::MakeString(v.translation.x) + ", " +
sconv::MakeString(v.translation.y) + ", " + sconv::MakeString(v.translation.z) + ")");
}

//Unlock the buffers for other parts of the program to access them if desired.
if (m_vbuffer->Unlock() != D3D_OK) { g_log->out("Vertex buffer unlock unsuccessful"); }
if (m_ibuffer->Unlock() != D3D_OK) { g_log->out("Index buffer unlock unsuccessful"); }
}


//Render: Display all of this to the screen.
void RenderingManager::Render()
{
//Set the world transform.
if (g_engine->GetDevice()->SetTransform(D3DTS_WORLD, m_camera->GetWorldMatrix()) != D3D_OK) { g_log->out("SetTransform failed"); }

//Draw that shiznit, yo.
if (g_engine->GetDevice()->SetFVF(TL_VERTEX_FVF) != D3D_OK) { g_log->out("SetFVF failed"); }
if (g_engine->GetDevice()->SetStreamSource(0, m_vbuffer, 0, TL_VERTEX_FVF_SIZE) != D3D_OK) { g_log->out("SetStreamSource failed"); }
if (g_engine->GetDevice()->SetIndices(m_ibuffer) != D3D_OK) { g_log->out("SetIndices failed"); }
//g_engine->GetDevice()->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, numVerts, 0, numTris);
if (g_engine->GetDevice()->DrawPrimitiveUP(D3DPT_TRIANGLELIST, 4, vertices, TL_VERTEX_FVF_SIZE) != D3D_OK) { g_log->out("DrawPrimitiveUP failed"); }
}





Main.cpp: a piece of code which fills the rendering manager with points (this is in the Load() function of a child class of State).


g_renderManager->SetCamera(m_camera);

//Add some points to make a tetrahedron.
int points[4];
points[0] = g_renderManager->AddVertex(TLVertex(D3DXVECTOR4(-10.0f, 10.0f, 3.0f, 1.0f), D3DCOLOR_RGBA(0, 0, 200, 255)));
points[1] = g_renderManager->AddVertex(TLVertex(D3DXVECTOR4(10.0f, 10.0f, 3.0f, 1.0f), D3DCOLOR_RGBA(0, 0, 200, 255)));
points[2] = g_renderManager->AddVertex(TLVertex(D3DXVECTOR4(0.0f, -5.0f, 3.0f, 1.0f), D3DCOLOR_RGBA(0, 0, 200, 255)));
points[3] = g_renderManager->AddVertex(TLVertex(D3DXVECTOR4(0.0f, 0.0f, -10.0f, 1.0f), D3DCOLOR_RGBA(0, 0, 200, 255)));
g_renderManager->AddFace(points[0], points[1], points[2]);
g_renderManager->AddFace(points[0], points[3], points[1]);
g_renderManager->AddFace(points[0], points[2], points[3]);
g_renderManager->AddFace(points[1], points[3], points[2]);
g_renderManager->CreateBuffers();





Output from CreateBuffers' testing section:

[00001045] Index 0 points to vertex (-10, 10, 3)
[00001045] Index 1 points to vertex (10, 10, 3)
[00001045] Index 2 points to vertex (0, -5, 3)
[00001045] Index 0 points to vertex (-10, 10, 3)
[00001045] Index 3 points to vertex (0, 0, -10)
[00001045] Index 1 points to vertex (10, 10, 3)
[00001045] Index 0 points to vertex (-10, 10, 3)
[00001045] Index 2 points to vertex (0, -5, 3)
[00001045] Index 3 points to vertex (0, 0, -10)
[00001045] Index 1 points to vertex (10, 10, 3)
[00001045] Index 3 points to vertex (0, 0, -10)
[00001045] Index 2 points to vertex (0, -5, 3)


TLVertex struct definition:


//TLVertex struct: Holds the data for a vertex that's been transformed and lit.
//Fractal doesn't use textures, instead relying on colour values.
struct TLVertex
{
D3DXVECTOR4 translation;
D3DCOLOR diffuse;

//Default constructor...
TLVertex() {
translation = D3DXVECTOR4(0.0f, 0.0f, 0.0f, 1.0f);
diffuse = 0xFFFFFFFF;
}

//...parameterised constructor.
TLVertex(D3DXVECTOR4 t, D3DCOLOR d) : translation(t), diffuse(d) {}
};
#define TL_VERTEX_FVF (D3DFVF_XYZRHW | D3DFVF_DIFFUSE)
#define TL_VERTEX_FVF_SIZE D3DXGetFVFVertexSize(TL_VERTEX_FVF)




SceneObject.cpp: Constructor and Update(). A SceneObject is just a basic thing with position, velocity, acceleration, etc. You can move it around using forces or just reposition it manually. Either way, it has a world matrix and a view matrix and those are important.


//Constructor: Zeros out values by default. Calls to Set(whatever) are used to assign most values.
SceneObject::SceneObject(unsigned long type, float mass, float maxSpeed)
{
//Set the object's type.
SetType(type);

//m_cpt is the multiplier that converts from a straight-line acceleration or velocity value to a rotational one.
//It is constant and is used by SetMaxSpeed, so needs to be set now.
m_cpt = (float)(CIRCLES_PER_1000 * pi / 500);

//mass and maxSpeed are also to be set. The setters perform some calculations for me, hence why I'm using them.
if (mass > 0) SetMass(mass);
else SetMaxSpeed(maxSpeed);

//Set the object's position and movement to absolutely nothing, and zero all the forces, too.
//StopMoving() does most of that.
SetTranslation(D3DXVECTOR3(0.0f, 0.0f, 0.0f));
SetRotation(D3DXVECTOR3(0.0f, 0.0f, 0.0f));
StopMoving();

//Face the direction of the positive Z-axis, soldier!
m_forward = D3DXVECTOR3(0.0f, 0.0f, 1.0f);
m_right = D3DXVECTOR3(1.0f, 0.0f, 0.0f);

//The object is visible and enabled by default.
m_visible = true;
m_enabled = true;

//The first time it's updated, we need to set the view and world matrices, and some other stuff too.
hasMoved = true;
//We don't necessarily need to set the forward and right vectors, though, 'cos we've just done it.
hasRotated = false;
}


//Update: Resolves movement, rotation and physics, updating the object's world matrix as necessary.
//Update has about a billion nasty multiplications in it, but at least it's O(1) asymptotically.
//I've also optimised it quite heavily, using m_cpt and m_maxSpinSpeed to save on recomputation and conditionals to ensure that the minimum necessary is done.
void SceneObject::Update(float elapsed)
{
/* GIANT SNIP - Cutting out vast amounts of movement/rotation code */

//Now that the object has been repositioned as necessary, we need to do some housekeeping-type stuff to ensure it interacts properly with the rest of the engine.
if (hasMoved || hasRotated) {
//Update the object's world matrix.
D3DXMatrixMultiply(&m_worldMatrix, &m_rotationMatrix, &m_translationMatrix);

//Create a view matrix for the object.
D3DXMatrixInverse(&m_viewMatrix, NULL, &m_worldMatrix);
}

if (hasRotated) {
//Update the object's forward vector.
m_forward.x = (float)sin(m_rotation.y);
m_forward.y = (float)-tan(m_rotation.x);
m_forward.z = (float)cos(m_rotation.y);
D3DXVec3Normalize(&m_forward, &m_forward);

//Update the object's right vector.
m_right.x = (float)cos(m_rotation.y);
m_right.y = (float)tan(m_rotation.z);
m_right.z = (float)-sin(m_rotation.y);
D3DXVec3Normalize(&m_right, &m_right);

//hasRotated can be set to false in here to avoid setting it repetitively for immobile objects (which might cause cache misses).
hasRotated = false;
}

if (hasMoved) {
//Update the object's bounding volume using the translation matrix only.
//This will maintain a bounding box aligned to the world axes, which can be checked against more quickly.
RepositionBoundingVolume(&m_translationMatrix);

//See comment for hasRotated.
hasMoved = false;
}
}



I think that's all the immediately relevant stuff. Feel free to request more. Thanks in advance for your help! :)

Share this post


Link to post
Share on other sites
First, a bit of advice: if you wrote that much code without testing it, you need to change your coding technique. Suggestion - for your next project, start with a very simple rendering loop and ensure it works. Then make a small change and test it again. You have so much that could go wrong - some sort of near-plane/far-plane scaling, camera parameter loading, etc. There's no way for someone looking at your code to determine if any of that may be causing a problem.

That being said:
Quote:
DrawPrimitiveUP(D3DPT_TRIANGLELIST, 4, vertices, TL_VERTEX_FVF_SIZE)

It looks like you load 4 vertices and attempt to render 4 triangles without using the index buffer (even though you set it - confusing). For 4 triangles you would need 12 vertices. Otherwise you should be rendering an indexed primitive.

Share this post


Link to post
Share on other sites
Thanks Buckeye. Most of this code is actually tested, as much as is possible. The only new thing is the RenderingManager.cpp and the tetrahedron definition stuff from Main.cpp. A lot of it's based on source code from a book. Also, the second argument in DrawPrimitiveUP is the number of primitives, not vertices. http://msdn.microsoft.com/en-us/library/bb174372(v=vs.85).aspx

Update:

I just set the background to white again and, this time devoid of text, realised that there are in fact a couple of points from a tiny triangle visible in the upper left hand corner, with lines drawn between them. One of the lines is flat and is probably supposed to be the one from (-10, 10, 3) to (10, 10, 3). The other heads towards the corner and is probably the line going to (0, -5, 3).

I enlarged some numbers and finally got something to appear!

Log output:
[000001108] Index 0 points to vertex (50, 50, 0)
[000001108] Index 1 points to vertex (350, 50, 0)
[000001108] Index 2 points to vertex (200, 350, 0)

This gives a big, point-down triangle in blue:



The window is 640x480.

Any ideas how I can make this obey the camera properly? Moving the camera around does nothing to the triangle. Rendering flat to the screen is fine for text but doesn't cut it for 3D...

edit: Ahhhhh of course... I have to actually apply the perspective transformation manually or something, don't I? Is there an easy/semi-automated way to do that?

Share this post


Link to post
Share on other sites
Ahhh, I was thinking it might be that. I tried changing it earlier and it didn't work, but there may have been another problem as well or something. Thanks. Should I use D3DFVF_XYZ | D3DFVF_DIFFUSE, or D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_NORMAL?

Share this post


Link to post
Share on other sites
You can try set:

//d3ddev->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
//d3ddev->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
d3ddev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);

to test if your triangles winding order are right with/without your indices.

edit: Ive never used DrawPrimitiveUP so i have no clue in wich order are triangles
culled without indices and iam to lazy to check for it with google. I guess it has
to do in order they are created.

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