[sldev] Sculpted prim works in progress
John Hurliman
jhurliman at wsu.edu
Sun Apr 29 16:11:55 PDT 2007
I got the MEL script for creating the sculpted prim textures working but
had no way to test if I did it right or not, so I wrote this:
http://www.jhurliman.org/images/sculptedpreview03.png
It's a C# XNA app, code is attached. One thing that I noticed was my own
position maps (is there a better name for them? that's what I've been
calling the textures) create geometry virtually identical to what I see
in Maya, but the ones I downloaded off of flickr appear to suffer from
slight JPEG compression artifacts. Will we be able to upload the
position maps using lossless JPEG2000 settings? Even the raw image files
only take up ~12.5KB.
John Hurliman
-------------- next part --------------
#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
#endregion
namespace sculptedpreview
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class SculptedPreview : Microsoft.Xna.Framework.Game
{
const string filename = "input.bmp";
const int LOD = 64;
GraphicsDeviceManager graphics;
ContentManager content;
private BasicEffect effect;
Texture2D positionMap;
VertexPositionColor[] vertexGrid;
ushort[] inds;
VertexBuffer vertexBuffer;
IndexBuffer indexBuffer;
SpriteBatch batch;
Rectangle topleft = new Rectangle(0, 0, 64, 64);
public SculptedPreview()
{
graphics = new GraphicsDeviceManager(this);
content = new ContentManager(Services);
Window.AllowUserResizing = true;
}
/// <summary>
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base.Initialize will enumerate through any components
/// and initialize them as well.
/// </summary>
protected override void Initialize()
{
vertexGrid = new VertexPositionColor[LOD * LOD];
inds = new ushort[LOD * LOD * 6];
batch = new SpriteBatch(graphics.GraphicsDevice);
// Setup the effect. Turn off all the lighting stuff until we are calculating normals
effect = new BasicEffect(graphics.GraphicsDevice, null);
//effect.Alpha = 1.0f;
//effect.DiffuseColor = new Vector3(1.0f, 1.0f, 1.0f);
//effect.AmbientLightColor = new Vector3(0.2f, 0.2f, 0.2f);
//effect.SpecularColor = new Vector3(0.0f, 0.0f, 0.0f);
//effect.SpecularPower = 0.2f;
//effect.AmbientLightColor = new Vector3(0.15f, 0.15f, 0.2f);
//effect.DirectionalLight0.Enabled = true;
//effect.DirectionalLight0.DiffuseColor = Vector3.One;
//effect.DirectionalLight0.Direction = Vector3.Normalize(new Vector3(0.0f, 0.0f, -1.0f));
//effect.DirectionalLight0.SpecularColor = Vector3.One;
//effect.LightingEnabled = true;
effect.Projection = Matrix.CreatePerspectiveFieldOfView(
(float)Math.PI / 4.0f, // 2 PI Radians is 360 degrees, so this is 45 degrees
(float)Window.ClientBounds.Width / (float)Window.ClientBounds.Height,
0.1f, 2048.0f);
effect.World = Matrix.CreateTranslation(new Vector3(0.0f, 0.0f, 0.0f));
effect.View = Matrix.CreateLookAt(new Vector3(1.0f, 1.0f, 1.0f), new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.0f, 1.0f, 0.0f));
base.Initialize();
}
/// <summary>
/// Load your graphics content. If loadAllContent is true, you should
/// load content from both ResourceManagementMode pools. Otherwise, just
/// load ResourceManagementMode.Manual content.
/// </summary>
/// <param name="loadAllContent">Which type of content to load.</param>
protected override void LoadGraphicsContent(bool loadAllContent)
{
if (loadAllContent)
{
// TODO: Load any ResourceManagementMode.Automatic content
}
try
{
// Load the position map input file
positionMap = Texture2D.FromFile(graphics.GraphicsDevice, filename);
}
catch (System.IO.FileNotFoundException)
{
Exit();
return;
}
// Create the vertex buffer
for (int y = 0; y < LOD; y++)
{
for (int x = 0; x < LOD; x++)
{
// Get the position map data
Color[] bits = new Color[positionMap.Width * positionMap.Height];
positionMap.GetData<Color>(bits);
// Create a vertex position from the RGB channels in the current pixel
Vector3 position = new Vector3(
((float)bits[y * LOD + x].R - 128) / 256.0f,
((float)bits[y * LOD + x].G - 128) / 256.0f,
((float)bits[y * LOD + x].B - 128) / 256.0f);
vertexGrid[y * LOD + x] = new VertexPositionColor(position, Color.Red);
}
}
vertexBuffer = new VertexBuffer(graphics.GraphicsDevice, typeof(VertexPositionColor), vertexGrid.Length,
ResourceUsage.WriteOnly);
vertexBuffer.SetData<VertexPositionColor>(vertexGrid);
// Create the index buffer
int i = 0;
for (int y = 0; y < LOD - 1; y++)
{
for (int x = 0; x < LOD - 1; x++)
{
inds[i++] = (ushort)(y * LOD + x);
inds[i++] = (ushort)(y * LOD + (x + 1));
inds[i++] = (ushort)((y + 1) * LOD + (x + 1));
inds[i++] = (ushort)(y * LOD + x);
inds[i++] = (ushort)((y + 1) * LOD + x);
inds[i++] = (ushort)((y + 1) * LOD + (x + 1));
}
// Wrap the last cell in the row around
inds[i++] = (ushort)(y * LOD + (LOD - 1));
inds[i++] = (ushort)(y * LOD);
inds[i++] = (ushort)((y + 1) * LOD);
}
indexBuffer = new IndexBuffer(graphics.GraphicsDevice, sizeof(ushort) * inds.Length, ResourceUsage.None,
IndexElementSize.SixteenBits);
indexBuffer.SetData<ushort>(inds, 0, inds.Length, SetDataOptions.None);
}
/// <summary>
/// Unload your graphics content. If unloadAllContent is true, you should
/// unload content from both ResourceManagementMode pools. Otherwise, just
/// unload ResourceManagementMode.Manual content. Manual content will get
/// Disposed by the GraphicsDevice during a Reset.
/// </summary>
/// <param name="unloadAllContent">Which type of content to unload.</param>
protected override void UnloadGraphicsContent(bool unloadAllContent)
{
if (unloadAllContent)
{
content.Unload();
}
// Unload any ResourceManagementMode.Manual content
}
/// <summary>
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input and playing audio.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
base.Update(gameTime);
}
/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
graphics.GraphicsDevice.RenderState.FillMode = FillMode.Solid;
// Draw the original position map in the top-left corner
batch.Begin(SpriteBlendMode.None, SpriteSortMode.Immediate, SaveStateMode.None);
batch.Draw(positionMap, topleft, Color.White);
batch.End();
using (VertexDeclaration decl =
new VertexDeclaration(graphics.GraphicsDevice, VertexPositionColor.VertexElements))
{
graphics.GraphicsDevice.VertexDeclaration = decl;
graphics.GraphicsDevice.RenderState.CullMode = CullMode.None;
graphics.GraphicsDevice.RenderState.FillMode = FillMode.WireFrame;
graphics.GraphicsDevice.Vertices[0].SetSource(vertexBuffer, 0, VertexPositionColor.SizeInBytes);
graphics.GraphicsDevice.Indices = indexBuffer;
effect.Begin();
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
{
pass.Begin();
graphics.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, vertexGrid.Length,
0, inds.Length / 3);
pass.End();
}
effect.End();
}
base.Draw(gameTime);
}
}
}
More information about the SLDev
mailing list