programatically using ScreenSpaceLines3D?

Topics: Developer Forum
Feb 13, 2007 at 11:34 AM
hi,
i'm new to WPF and 3D in general, i have a working application with a cube and slider controls to manipulate the camera position and look vector.

i'd like to draw a 10x10 3D grid to fill the space. can i use ScreenSpaceLines3D for this? the source class file shows hard-coded usage in xaml, but i'm interested in programmatic use. the code i have is below, i know it will just result in a mangle of lines, but that would be a good start!
private void DrawGrid()
{
	ScreenSpaceLines3D grid = new ScreenSpaceLines3D();
	for(int i=0; i<10; i++)
		for(int j=0; j<10; j++)
			for(int k=0; k<10; k++)
				grid.Points.Add(new Point3D(i,j,k)); 
	grid.Color = Colors.Azure;
	grid.Thickness = 3;
	this.mainViewport.Children.Add(grid);
}
i noticed the MakeWireFrame() method, but i don't have any Model3D objects to do that with.
any tips / pointers?

many thanks in advance
tim

p.s. here's my xaml in case it's useful, i have stripped down the code-behind just to draw the grid in the OnLoaded event.
<Window x:Class="WPF_Test.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	xmlns:tools="clr-namespace:_3DTools;assembly=3DTools"
    Title="WPF_Test" Height="320" Width="458" WindowState="Maximized"
    >
	<Grid ShowGridLines="True" Name="WorldGrid">
		<DockPanel
		 Width="Auto"
		 VerticalAlignment="Stretch"
		 Height="Auto"
		 HorizontalAlignment="Stretch"
		 Grid.ColumnSpan="1"
		 Grid.Column="0"
		 Grid.Row="0"
		 Margin="0,0,0,0"
		 Grid.RowSpan="1"
		>
			<StackPanel>
				<StackPanel.Background>
					<LinearGradientBrush>
						<GradientStop Color="White" Offset="0"/>
						<GradientStop Color="DarkKhaki" Offset=".3"/>
						<GradientStop Color="DarkKhaki" Offset=".7"/>
						<GradientStop Color="White" Offset="1"/>
					</LinearGradientBrush>
				</StackPanel.Background>
				<StackPanel Margin="10">
					<Button
					 Name="simpleButton"
					 Click="simpleButtonClick">Create</Button>
					<TextBlock  Text="Camera X:" />
					<Slider ValueChanged="SetCamera"  Name="slider1" VerticalAlignment="Top" Width="104" Maximum="100" Minimum="0" />
					<TextBlock  Text="Camera Y:" />
					<Slider ValueChanged="SetCamera"  Name="slider2" VerticalAlignment="Top" Width="104" Maximum="100" Minimum="0" />
					<TextBlock  Text="Camera Z:" />
					<Slider ValueChanged="SetCamera"  Name="slider3" VerticalAlignment="Top" Width="104" Maximum="100" Minimum="0" />
        </StackPanel>
			</StackPanel>
			<Border Name="WrapPanel" Background="Transparent">
				<Viewport3D Name="mainViewport"  ClipToBounds="True">
					<Viewport3D.Camera>
						<PerspectiveCamera
						  FarPlaneDistance="100"
						  NearPlaneDistance="0"
						  LookDirection="0,0,-1"
						  UpDirection="0,1,0"
						  Position="50,50,75"
						  FieldOfView="70"
					 />
					</Viewport3D.Camera>
					<ModelVisual3D>
						<ModelVisual3D.Content>
							<DirectionalLight
							 Color="White"
							 Direction="0,0,-1" />
						</ModelVisual3D.Content>
					</ModelVisual3D>
				</Viewport3D>
			</Border>
    </DockPanel>
		<DockPanel Width="Auto"
		 VerticalAlignment="Bottom"
		 Height="Auto"
		 HorizontalAlignment="Stretch"
		 Grid.ColumnSpan="1"
		 Grid.Column="0"
		 Grid.Row="1"
		 Margin="0,0,0,0"
		 Grid.RowSpan="1">
			<StatusBar Name="statusBar1" VerticalAlignment="Bottom">
				<StatusBarItem HorizontalAlignment="Left" Name="statusBarItem1" ></StatusBarItem>
			</StatusBar>
		</DockPanel>
    </Grid>
</Window>
Coordinator
Feb 15, 2007 at 2:58 AM
Yep, you can use ScreenSpaceLines3D to draw your grid. ScreenSpaceLines3D has a DependencyProperty Points that holds the points that will be drawn. To draw your grid you just need to set those points to be the locations of the lines you want to draw. Here's some sample psuedocode to hopefully illustrate it:

ScreenSpaceLines3D ssl3D = new ScreenSpaceLines3D();

Point3DCollection gridLines = new Point3DCollection();
foreach (line segment in your grid)
{
gridLines.Add(start point);
gridLines.Add(end point);
}

ssl3D.Points = gridLines;

Hopefully that does the trick. Let me know if it doesn't.

-Kurt
Feb 15, 2007 at 9:41 AM
hi kurt.
many thanks for the reply. the code you posted is symantically similar to what i already have, but nothing is rendered to the viewport.

i found an alternative way of drawing a line, essentially a long thin cuboid. it works quite nicely but is probably not great for performance. i'd like to get the ScreenSpaceLines3D class working if possible.

here is the code i'm trying with the ScreenSpaceLines3D class:

ScreenSpaceLines3D ssl3D = new ScreenSpaceLines3D();
Point3DCollection gridLines = new Point3DCollection();
 
for (int i = 0; i <= size; i++)
{
	for (int j = 0; j <= size; j++)
	{
		// convert the loop iterators into the required grid cell size interval, relative to len
		double a = i * interval;
		double b = j * interval;
 
		// x line
		gridLines.Add(new Point3D(0, a, b));
		gridLines.Add(new Point3D(len, a, b));
 
		// y line
		gridLines.Add(new Point3D(a, 0, b));
		gridLines.Add(new Point3D(a, len, b));
 
		// z line
		gridLines.Add(new Point3D(a, b, 0));
		gridLines.Add(new Point3D(a, b, len));
	}
}
ssl3D.Points = gridLines;
ssl3D.Color = Colors.Red;
ssl3D.Thickness = 5;
this.mainViewport.Children.Add(ssl3D);

i'm also using the TrackBall class as follows:
void Window1_Loaded(object sender, RoutedEventArgs e)
{
	Trackball trackball = new Trackball();
	trackball.EventSource = this.WrapPanel;
	this.mainViewport.Camera.Transform = trackball.Transform;
} 

i should point out that i have no difficulty in getting 3d objects to appear in the viewport, using standard cubes / triangles etc. it's just that the ScreenSpaceLines3D objects won't render. am i doing something wrong?
one other thing, i noticed if you click on an object (e.g. cube) 3 times in a row, the TrackBall class chucks an exception, line 27, InvalidOperationException, "zero axis of rotation specified". Quaternion delta = new Quaternion(axis, -angle); probably because i clicked without dragging?

TrackBall is a really great class, and a major help in building 3d applications, thanks for making it freely available. i notice the zoom always goes towards the origin. could you say if it's possible to zoom in the look vector of the camera instead? just out of interest! if you pointed me in the right direction i'd be glad to try and modify the code.

cheers
tim
Coordinator
Mar 20, 2007 at 7:14 PM
Sorry for the slow response. I took the Channel9 Demo code, and took your above code and added it (putting in values for size, interval, len), and was able to get it to show. Are you sure that your camera is able to see your ScreenSpaceLine output?

I think the TrackBall issue you mention is a bug we have with the Trackball class, but that I believe got fixed with TrackballDecorator. I'll make sure to fix the TrackBall in a future release.

I hadn't noticed that behavior of the trackball, but I can see it now. I'll make sure to fix that in future releases. What you can do is that rather than tweaking a ScaleTransform on the camera, you can just adjust the camera's field of view. Shrinking the field of view will cause a zoom, while increasing it will cause you to zoom out.
Oct 26, 2007 at 2:34 PM
Hi also trying to using TrackballDecorator to retrieve the current mouse position and skeins a mesh on that position could no success.
Mar 28, 2008 at 1:48 PM
I meet the same problem, I can't see any line too... Can somebody offer some available codes, thanks!
Apr 30, 2008 at 3:57 PM
I think it has something to do with redrawing the scene. I was able to get it to do this by calling the Viewport3D.InvalidateVisual() method. Of course I am not sure if this is the proper way to refresh the scene, let me know if there is a better way of handling this.