Jump to content

  • Log In with Google      Sign In   
  • Create Account

Rendering Systems



Woody3D Discontinued

Posted by , in Woody3D 17 July 2012 - - - - - - · 1,814 views

I'll just post what I wrote on the woody3d.com website, then I'll explain...

"Woody3D was developed by Neil Kemp at Rendering Systems Inc. as an inexpensive solution for developers to bring fully animated trees and foliage to their applications and engines. Woody3D was discontinued in July 2012.

Real-time tree generation and animation remain a core focus for Neil and Rendering Systems. In the future they’ll place a higher emphasis on modeling tools and less on source code integration."

Woody3D was a long term comitment for me. Three years of development. I wanted to create affordable real-time trees for developers. Why did it fail? Simple, the technology was complex and not easily integrated into today's popular engines. It focused more on source code integration and had a very nerdy user inteface. It should have focused on a simple intuitive interface (draw the tree - grab and bend the branches, etc.) with easy export to popular file formats.

So that's what I plan to do. Start again. I believe I can take what learned from Woody3D (and ShaderMap 2) to build a better (single) tool to generate fully animated 3D trees and plants for video games, simulations, and software rendering systems. I can't fail if I don't quit.

The Woody3D Field of Trees video will remain online:




Woody3D.pause() ShaderMap2.play()

Posted by , in ShaderMap, Woody3D 17 June 2011 - - - - - - · 672 views

woody3d.pause()

As it stands Woody still requires a couple more months of development to be ready for the next release. I'm really excited about all of the new features in the upcoming release but I've been developing Woody3D for about 3 years. That's a long time for a single developer to work on a project with no end in sight and little reward... I need a break.

Or rather...

I need a finite project to work on.

shadermap2.play()

Earlier this week, I began implementing the interface I'd previously drawn in PhotoShop.

Posted Image

It's built using C++and Direct3D 9 in a Win32 framework. All controls are derived from a ui_base class which maintains a list of children controls and provides an interface for event callbacks, updates, and drawing.

Here's what I've done on the interface so far:
  • Tool tip support
  • Drag and drop support
  • UI framework
  • Button control
  • Checkbox control
  • ShaderMap 2 icon artwork
  • Menu interface
  • Start page

I'll continue developing the UI then do an open test here and on the ShaderMap forums to get all the bugs worked out. Then I'll get to work on the plugin system.

Woody fans have no fear, development will .play() soon after ShaderMap2 is released. Switching projects has already brought my energy levels back near immortal levels.



Roots and "Tree" Hierarchy Control

Posted by , in MFC, Woody3D 03 June 2011 - - - - - - · 960 views

Posted Image

Woody3D can create tree roots as shown above. There is a problem however, as it currently uses a very simple hierarchy for branch levels. It does not allow for more than one child per branch. This means you can add roots but not branches. That's a pretty boring tree.

Next version will support a more flexible hierarchy. To manage the various parts of the tree, I'll be using a CtreeCtrl in the Tree Forge. Below is a colored
CtreeCtrl (with fancy gradient selection bar).

Posted Image

And here is the source for the control if you're interested in how it works. Feel free to modify it and use it in your own MFC projects.

Color_Tree.h
#ifndef ___COLOR_TREE_CONTROL_H___
#define ___COLOR_TREE_CONTROL_H___


class Color_Tree : public CTreeCtrl
{
private:
	
	COLORREF							___select_background_color;
	COLORREF							___select_font_color;
	COLORREF							___lost_focus_select_background_color;
	COLORREF							___lost_focus_select_font_color;

	BOOL								___is_select_full_row;
	BOOL								___is_select_full_row_gradient;

protected:

	DECLARE_MESSAGE_MAP()
	
	afx_msg	void						OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult);
	
public:

	// Constructor / Destructor
	Color_Tree(void);
	~Color_Tree(void);

	void								enable_select_full_row(BOOL enable, BOOL is_gradient);
	void								set_select_color(COLORREF select_background_color, COLORREF select_font_color, 
													     COLORREF lost_focus_select_background_color, COLORREF lost_focus_select_font_color);
};


#endif

Color_Tree.cpp
#include "stdafx.h"
#include "Color_Tree.h"
 


// Local Gradient rectangle function
BOOL draw_gradient_rect(CDC *pDC,
              	const CRect &draw_rect,
              	const COLORREF start_color,
              	const COLORREF end_color,
              	const bool is_horizontal)
{
	// Local data
	BYTE				red_start, green_start, blue_start, 
						red_end, green_end, blue_end; 
	TRIVERTEX			vertex_array[2] = { 0 };
	GRADIENT_RECT		gradient_rect[1] = { 0 };


	// Validate DC
	if(!pDC || !pDC->GetSafeHdc())
	{	return FALSE;
	}

	// Get RGB bytes from start color
	red_start				= GetRValue(start_color);
	green_start				= GetGValue(start_color);
	blue_start				= GetBValue(start_color);

	// Set first vertex
	vertex_array[0].x		= draw_rect.left;
	vertex_array[0].y		= draw_rect.top;
	vertex_array[0].Red		= (static_cast<USHORT>(red_start)   << 8);
	vertex_array[0].Green	= (static_cast<USHORT>(green_start) << 8);
	vertex_array[0].Blue	= (static_cast<USHORT>(blue_start)  << 8);
	vertex_array[0].Alpha	= 0x0000;

	// Get RGB bytes from end color
	red_end					= GetRValue(end_color);
	green_end				= GetGValue(end_color);
	blue_end				= GetBValue(end_color);

	// Set second vertex
	vertex_array[1].x		= draw_rect.right;
	vertex_array[1].y		= draw_rect.bottom;
	vertex_array[1].Red		= (static_cast<USHORT>(red_end) 	<< 8 );
	vertex_array[1].Green	= (static_cast<USHORT>(green_end)   << 8 );
	vertex_array[1].Blue	= (static_cast<USHORT>(blue_end)	<< 8 );
	vertex_array[1].Alpha	= 0x0000;

	// Gradient vertex index	
	gradient_rect[0].UpperLeft  = 0;
	gradient_rect[0].LowerRight = 1;

	// Draw gradient rect
	return GradientFill( pDC->GetSafeHdc(),
					     vertex_array, 
					     2,
					     &gradient_rect, 
					     1,
					     is_horizontal ? GRADIENT_FILL_RECT_H : GRADIENT_FILL_RECT_V ) == TRUE;
}

// c()
Color_Tree::Color_Tree(void)
{	
	___is_select_full_row			= FALSE;
	___is_select_full_row_gradient	= FALSE;
}
// d()
Color_Tree::~Color_Tree(void)
{
}

// Message map
BEGIN_MESSAGE_MAP(Color_Tree, CTreeCtrl)	
	ON_NOTIFY_REFLECT( NM_CUSTOMDRAW, OnCustomDraw)
END_MESSAGE_MAP()


// Handle color of select
void Color_Tree::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult)
{	
	// Local data
	NMTVCUSTOMDRAW*		pcd;
	RECT				rect;
	CDC*				pDC;
	CBrush				brush;


	// Get custom draw struct
	pcd = (NMTVCUSTOMDRAW*)pNMHDR;

	// Handle by draw stage
	switch(pcd->nmcd.dwDrawStage)
	{
	case CDDS_PREPAINT: 

    	*pResult = CDRF_NOTIFYITEMDRAW;

    	break;
		// Pre paint of tree item
	case CDDS_ITEMPREPAINT: 
   	
		// To Get item
    	HTREEITEM hItem = (HTREEITEM)pcd->nmcd.dwItemSpec;
		
		// Handle control has focus
		if(this->GetFocus() == this)
		{	
			// If item is selected
			if(pcd->nmcd.uItemState & CDIS_SELECTED)
			{
				pcd->clrText	= ___select_font_color;	
				pcd->clrTextBk	= ___select_background_color;

				// Determine if item is in view
				// Get text rect
				if(___is_select_full_row && this->GetItemRect(hItem, &rect, TRUE))
				{
					// Adjust rect
					pcd->nmcd.rc.left = rect.right;

					// Gradient fill
					if(___is_select_full_row_gradient)
					{
						// Get DC and fill
						pDC = this->GetDC();
						draw_gradient_rect(pDC, pcd->nmcd.rc, ___select_background_color, this->GetBkColor(), true);

						// Cleanup
						this->ReleaseDC(pDC);
					}
					// Solid fill
					else
					{
						// Get DC and Create brush
						pDC = this->GetDC();				
						brush.CreateSolidBrush(___select_background_color);					
						
						// Solid fill
						pDC->FillRect(&pcd->nmcd.rc, &brush);
					
						// Cleanup
						brush.DeleteObject();
						this->ReleaseDC(pDC);
					}
				}
			}
			// If item is hot (mouse over)
			else if(pcd->nmcd.uItemState & CDIS_HOT)
			{
			     pcd->clrText	= this->GetTextColor();
			}			
		}
		else
		{
			// If item is selected
			if(pcd->nmcd.uItemState & CDIS_SELECTED)
			{
				pcd->clrText	= ___lost_focus_select_font_color;	
				pcd->clrTextBk	= ___lost_focus_select_background_color;

				// Determine if item is in view
				// Get text rect
				if(___is_select_full_row && this->GetItemRect(hItem, &rect, TRUE))
				{
					// Adjust rect
					pcd->nmcd.rc.left = rect.right;

					// Gradient fill
					if(___is_select_full_row_gradient)
					{
						// Get DC and fill
						pDC = this->GetDC();
						draw_gradient_rect(pDC, pcd->nmcd.rc, ___lost_focus_select_background_color, this->GetBkColor(), true);

						// Cleanup
						this->ReleaseDC(pDC);
					}
					// Solid fill
					else
					{
						// Get DC and Create brush
						pDC = this->GetDC();					
						brush.CreateSolidBrush(___lost_focus_select_background_color);

						// Solid fill
						pDC->FillRect(&pcd->nmcd.rc, &brush);

						// Cleanup
						brush.DeleteObject();
						this->ReleaseDC(pDC);
					}
				}
			}
			// If item is hot (mouse over)
			else if(pcd->nmcd.uItemState & CDIS_HOT)
			{
			     pcd->clrText	= this->GetTextColor();
			}
		}

    	*pResult = CDRF_DODEFAULT;

    	break;
	}
}

// Enable select full row
void Color_Tree::enable_select_full_row(BOOL enable, BOOL is_gradient)
{	___is_select_full_row = enable;
	___is_select_full_row_gradient = is_gradient;
}

// Set the colors for selecting items
void Color_Tree::set_select_color(COLORREF select_background_color, COLORREF select_font_color, 
							  	COLORREF lost_focus_select_background_color, COLORREF lost_focus_select_font_color)
{
	___select_background_color				= select_background_color;
	___select_font_color					= select_font_color;
	___lost_focus_select_background_color	= lost_focus_select_background_color;
	___lost_focus_select_font_color			= lost_focus_select_font_color;
}

Example

	CImageList	___tree_image_list;
	Color_Tree	___tree_control;


	// Local data
	CBitmap		bitmap;
	HTREEITEM	o_1, o_2, c_1, c_2;


	// Setup tree colors
	___tree_control.SetBkColor(RGB(116, 127, 138));
	___tree_control.SetTextColor(RGB(255, 255, 255));
	___tree_control.SetLineColor(RGB(255, 255, 255));
	___tree_control.set_select_color(RGB(196, 210, 224), RGB(0, 0, 0), RGB(102, 114, 124), RGB(255, 255, 255));
		
	// Setup tree images
	___tree_image_list.Create(16, 16, ILC_COLOR32, 1, 4);	
	// Bitmap 1
	bitmap.LoadBitmap(IDB_BITMAP1);
	___tree_image_list.Add(&bitmap, RGB(0, 0, 0));
	bitmap.DeleteObject();
	// Bitmap 2
	bitmap.LoadBitmap(IDB_BITMAP2);
	___tree_image_list.Add(&bitmap, RGB(0, 0, 0));
	bitmap.DeleteObject();
	// Set image list
	___tree_control.SetImageList(&___tree_image_list, TVSIL_NORMAL);

	// Set item height
	___tree_control.SetItemHeight(20);

	// Custom enable select of whole row - do not use 'Full Row Select' property for Control - it disables lines
	// Allows for horizontal gradient too.
	___tree_control.enable_select_full_row(TRUE, TRUE);

	// Add items
	o_1 = ___tree_control.InsertItem(_T("Trunk"), 0, 0);
	c_1 = ___tree_control.InsertItem(_T("Standard Branch 0"), 1, 1, o_1);
	c_2 = ___tree_control.InsertItem(_T("Standard Branch 1"), 1, 1, o_1);
	___tree_control.InsertItem(_T("Imposter Branch 0"), 1, 1, c_2);
	o_2 = ___tree_control.InsertItem(_T("Leaf Types"), 0, 0);
	___tree_control.InsertItem(_T("Mesh Leaf 0"), 1, 1, o_2);
	___tree_control.InsertItem(_T("Billboard Leaf 0"), 1, 1, o_2);



Leaf Meshes vs. Leaf Billboards

Posted by , in Woody3D 01 June 2011 - - - - - - · 1,254 views

Posted Image

Above is a tree which uses spoke meshes for leaves (used imposter branches for leaves [see wire-frame render in comments]). Below is a tree which uses billboarded quads for leaves.

Posted Image

I'm thinking that mesh type leaves are the way forward. I'll keep support for billboards, they could be very useful for vines, but the next version will not rely on them exclusively. With mesh type leaves the user can choose from a palette of leaf mesh types. Also export to static formats would be possible.


What do you think?



My First SSAO and the BrushUp GUI

Posted by , in Graphics, Woody3D 25 May 2011 - - - - - - · 632 views

Posted Image

I've spent two days building SSAO with Direct3D. I used the method described in the GameDev.net article A Simple and Practical Approach to SSAO. After some tweeking I've got some decent results and speeds. It uses two buffers for normals and positions vs extracting position from depth and perspective. The result is blurred using a two-pass box blur.

Later today I'll start adding this AO implementation to the Leaf Painter. It should greatly improve the leaf textures.

In other news - the BrushUp Utlity GUI is finished. See below:


Posted Image

It has a re-sizable and intuitive interface with drag-and-drop list box and image preview. It uses an iterative thread scheduler to process cropped images based on CPU count. I'll release the scheduler source on my website when I get around to it.


Inside the BrushUp Utility

Posted by , in Woody3D 11 May 2011 - - - - - - · 631 views

Posted Image

One of the new utility apps (BrushUp) I'm developing for Woody3D will allow the artist to scan in a series of leaves in the field and with very little effort convert them to brush maps compatible with the Leaf Painter editor. This entry documents the process by which this is achieved.

For this example I've taken 8 leaves from one of my house plants, placed them vertically in the scanner, closed the lid, hit the button and the results are shown above.

What BrushUp does is take scans like the one above, detect and crop out each individual leaf, build alpha maps for each, expand the color edges, and save to a folder. It does this using the following steps.

Step 1. A little pre-processing. Load the scan into Photoshop and use the paint tool, with high tolerance and anti-alias disabled, to create a solid background color for the map.

Posted Image

Step 2. Load the image into BrushUp and tell it the background color.

Step 3. Enforce a 1 pixel border. To simplify edge detection we ensure there is a 1 pixel border of background color on the image. Canvas resize.

Step 4. Flood Fill Alpha to Zero where background color. This does two things. It defines the initial binary alpha map, and paints the edges of each brush with a 128 alpha. This will be used later when determining bounding rects for each brush. The flood fill uses 4 directions and is stack based. Pixels already added to the stack are marked with alpha 128. The resulting alpha map is shown below:

Posted Image

Step 5. Get a list of Bounding Rectangles for each Leaf / Brush. The alpha channel is scanned for every pixel. When a pixel with alpha 128 is found it uses an 8 direction stack based fill algorithm to follow the edge around, marking checked pixels white as it goes and maintaining min and max points to build the rectangle on completion.

Step 6: For every bounding rect Crop and Post Process. Iterate through the list of rects and do the following for each:
  • a) Crop the brush using rect.
  • b) Optionally give brush an n-pixel border.
  • c) Expand the color edges of the brush. This is a filter that pulls out edge colors making it easier to down-sample the brush image without destroying the edge colors.
  • d) Optionally apply smooth edges to alpha map. To do this it uses a Gaussian blur on the alpha channel where Alpha is 255.
  • e) Save the brush image to file.

A few of the resulting brush files are shown below:

Posted Image

And a couple of (I think 4) minutes later, I had created this texture in Leaf Painter using the new Palmate Compound node.

Posted Image



Compound Pinnate Changes

Posted by , in Woody3D 28 April 2011 - - - - - - · 319 views

Posted Image

Just made a change. There are now just two compound leaf types: Palmate and Pinnate. Compound pinnates, such as the one shown above, can be generated using a pinnate type node with pinnate type leaf textures. The result is acceptable. Moving on...



Compound Leaf Progress and New Tool Ideas

Posted by , in Woody3D 27 April 2011 - - - - - - · 740 views

Posted Image

I've made some progress with the procedurally generated compound leaf types in the Leaf Painter editor. There are three basic compound types to paint with: Palmate, Pinnate, and Compound Pinnate. Pinnate types can be made to be odd or even with optionally alternating leaf patterns.

There are a number of parameters that allow for scaling and rotating leaves along the length of the stem as well as modifiers for bending and angling each stem. I've added the curve editor to the Leaf Painter for additional control.

The leaves on each compound leaf are animated automatically. No more time consuming leaf animation setup. Click, adjust parameters, set orientation, and done. You can also set any compound leaf as the paint template - meaning the parameters of the template node will be used when painting additional nodes.

So far I've completed the palmate and pinnate types. An example of each is shown on the image above. Only one leaf texture is used at the moment.

---

There will be (at least) two new tools added to version 1.2. The first new tool is a map packer for combining multiple leaf maps and imposter branch maps into a single texture. It will also generate the map markers which Tree Forge uses to calculate uv frame data. Drag a few textures in, hit a button, it spits out a map.

The second tool will vastly improve the Leaf Painter brush making process. In the field I want to scan several leaves at a time. The brush maker tool will load the scanned image, detect and crop out the individual leaves, and generate and embed alpha masks into the resulting brush images. Currently doing this in Photoshop is exceedingly tedious.

I'll begin working on these tools once the compound leaf types are complete (I need a break from the Leaf Painter). After that I'll return to the Leaf Painter to add the ambient occlusion, multi-sampled rendering, and improved alpha maps which should wrap up 1.2 features for Leaf Painter.



Artists Like the Dark

Posted by , in Woody3D 04 April 2011 - - - - - - · 707 views

So I've spent a little while dimming the lights...

Posted Image

I think it's a big improvement.

Working hard to bring procedurally generated compound leaf types. After that... occlusion shading. If you're wondering, the interface is MFC +C+. All common controls are sub classed for custom colors and bitmaps. The property grid (right) is a custom control, made by me. The color picker uses the XColorSpectrum control by Hans Dietrich. Thanks Hans.

Will post again when I have some shots of the new compound leaf nodes. The images above still use the single leaf type geometry.



Woody3D 1.2 Development Begins

Posted by , in Woody3D 10 March 2011 - - - - - - · 414 views

Just a quick post to announce that Woody3D 1.2 development is underway. Below is a list of features being added to the SDK.

Leaf Painter – Will be maturing the Painter application nearer its full potential. Adding procedurally generated compound leaves (Compound Paint Tool) for fast drawing of leaf textures. That should also generate more realistic tangent space maps. Will be using the Woody procedural engine for stem mesh generation. Users will be able to select from a variety of leaf types when painting. Ambient shadows / shading will be added as well as non-binary alpha transparency for generated maps.

Tree Forge – Adding a tree wizard. Users will select from a tree shape, size, and polygonal resolution. The resulting tree can then be edited as normal. The wizard will be scripted so users can add their own plant types.

Tree Compiler – Allow trees and plants to be randomized at compile time. Ability to automatically generate multiple randomized mesh files. Useful if integrating into a game editor and want to randomize meshes during development using the command line version.

API – Adding an example demonstrating the rendering multiple trees in a scene. Creating a C# version of the API with examples.







Twitter

Posted Image

Google GameDev.Net Search Bar

Posted Image

Recent Comments



PARTNERS