Find centre point in autodesk maya - maya

how to find the centre point in autodesk maya...I know use the centre pivot but i can't find the point..how to find the exact coordinate of the 3d object created using autodesk maya? thanks.

Just go to the menus, Modify > Center Pivot. This will make your pivot go to the center of your model.

There are actually two possible answers to the question.
The 'center' of the object could mean:
The center of the object's bounding box : you could get this as follows (using python)
bbx = cmds.xform(object, q=True, bb=True, ws=True) # world space
centerX = (bbx[0] + bbx[3]) / 2.0
centerY = (bbx[1] + bbx[4]) / 2.0
centerZ = (bbx[2] + bbx[5]) / 2.0
the location of the object's pivot: This is not the same as the object's position, since you can move the pivot without changing the translation number that maya reports. The world-space pivot location can be gotten with:
pivot = cmds.xform(object, q=True, rp=True, ws=True)

If you're happy with where the center pivot command puts the pivot and you just want to know where in worldspace it is, you could do the following (assuming you have the object selected)
using PyMEL:
import pymel.core as pm
theObject = pm.ls(sl=1)[0]
theObject.getRotatePivot()
or using maya.cmds:
import maya.cmds as mc
mc.xform(query=True,rotatePivot=True)
or using MEL
xform -q -rotatePivot

There's actually a command called objectCenter()
This will give you true world space of a specific point or object.
import maya.cmds as cmds
# create a simple hierarchy
cmds.polyCube( name='a' )
cmds.polyCube( name='b' )
cmds.parent( 'b', 'a' )
cmds.move( 3, 0, 0, 'a', localSpace=True )
cmds.move( 2, 2, 2, 'b', localSpace=True )
X_COORD = cmds.objectCenter('b',x=True)
# Result: 5 #
# Get the center of the bounding box of b in local space
XYZ = cmds.objectCenter('b', l=True)
# Result: 2 2 2 #
# Get the center of the bounding box of b in world space
XYZ = cmds.objectCenter('b', gl=True)
# Result: 5 2 2 #
# Get the center of the bounding box of a in world space
XYZ = cmds.objectCenter('a', gl=True)
http://download.autodesk.com/global/docs/maya2013/en_us/CommandsPython/index.html
Shannon

Select the object and select: Animation > Create Deformers > Cluster.
A cluster deformer will now appear at the exact center of your object, denoted by a 'C', you can vertex-snap to the cluster whatever you need to have centered. The actual centerpoint of the cluster will be just below the 'C'.

In maya select object and look in panel on the right.

Select the object, and then run this in the script editor:
string $sel[];
$sel = `ls -sl`;
print `getAttr ($sel[0]+".translate")`;
This will print the X, Y, and Z coordinates in the history panel.

Select the object, "Modify-Center pivot.."
In case of not working, just select the object and press 'Insert key, in your key
board. then it will allow you to set pivot..just drag and drop the place where u want to set...
If you have any doubt feel free to share....

Related

Maya Python Mash - How can I add a selection set using Maya Mash API (in python)

Adding the cmds.connectAttr at the end does connect the selection set in Maya in the UI, but that's all it does. It acts as it its not registering.
import maya.cmds as cmds
import MASH.api as mapi
sel = cmds.ls(sl=1, l=1, fl=1)
new_set = cmds.sets(sel, n="custom_set")
obj_name = sel[0].split(".")[0]
shape = cmds.listRelatives(obj_name, s=True, f=1)
print(shape)
shape = "pCylinderShape1" #distribute mesh
cmds.select("|pCylinder2") #main mesh MASH
#create a new MASH network
mashNetwork = mapi.Network()
mashNetwork.createNetwork(name="Custom_placement", geometry="Repro")
shape = "pCylinderShape1"
mashNetwork.meshDistribute(shape, 4)
cmds.connectAttr(new_set+".message", mashNetwork.distribute+".selectionSetMessage")
Closest answer I found was here but I am not a programmer to know what that means.
If anyone can help, I'd much appreciate it.
After a lot of investigation I did manage to find the answer from the provided link.
The code I wrote was only the first part of the solution.
hasMASHFlag = cmds.objExists('%s.mashOutFilter' % (new_set))
if not hasMASHFlag:
cmds.addAttr( new_set, longName='mashOutFilter', attributeType='bool' )
cmds.setAttr( '%s.arrangement' % (mashNetwork.distribute), 4 )
cmds.setAttr( '%s.meshType' % (mashNetwork.distribute), 7 )
Note sure is needed but I noticed when you connect a selection set by default it has an extra attribute called mashOutFilter.
The part that is needed is the .meshType that makes it work.

How to use extra extra_x_ranges, extra_y_ranges with add_tile in bokeh

I want to use long/lat (EPSG:4326) coordinates in a bokeh plot and have a map in the Background.
I tried with the tile provider maps as suggested in bokeh: Mapping geo data.
But the format is in web mercator coordinates (EPSG:3857) and I don't want to convert my coordinates.
The general question how to do this is unanswered in Is it possible to set figure axis_type in bokeh to geographical (long/lat)?
My idea was to use extra axes:
from bokeh.plotting import figure, show
from bokeh.models import Range1d, LinearAxis
from bokeh.tile_providers import CARTODBPOSITRON, get_provider
tile_provider = get_provider(CARTODBPOSITRON)
p = figure(x_range=(-180, 180), y_range=(-90, 90)) # EPSG:4326
# add extra axis
p.extra_x_ranges = {"EPSG:3857x": Range1d(start=-20026376.39, end=20026376.39)}
p.extra_y_ranges = {"EPSG:3857y": Range1d(start=-20048966.10, end=20048966.10)}
# place extra axis
p.add_layout(LinearAxis(x_range_name="EPSG:3857x"), 'above')
p.add_layout(LinearAxis(y_range_name="EPSG:3857y"), 'right')
p.add_tile(tile_provider, x_range_name="EPSG:3857x", y_range_name="EPSG:3857y")
show(p)
But the map is not visible.
Is there a way to use extra axis for a tile_provider?
If you are just asking about displaying lat/lng visually on the axes, then all you have to do is set the axis type to "mercator"
p = figure(x_range=(-2000000, 6000000), y_range=(-1000000, 7000000),
x_axis_type="mercator", y_axis_type="mercator")
This is demonstrated on the documentation page you linked.
If you are asking about using data that is in lan/lng coordinates to plot on a tile plot, then you will need to convert it to Web Mercator first. The underlying coordinate system for tiles is always Web Mercator.
If you are asking about something else, then your question is not clear (please update to clarify).

CNN with RGB input and BW binary output

I am a beginner to deep learning and I am working with Keras built on top of Tensorflow. I am trying to using RGB images (540 x 360) resolution to predict bounding boxes.
My labels are binary (black/white) 2 dimensional np array of dimensions (540, 360) where all pixels are 0 except for the box edges which are a 1.
Like this:
[[0 0 0 0 0 0 ... 0]
[0 1 1 1 1 0 ... 0]
[0 1 0 0 1 0 ... 0]
[0 1 0 0 1 0 ... 0]
[0 1 1 1 1 0 ... 0]
[0 0 0 0 0 0 ... 0]]
There can be more than one bounding box in every picture. A typical image could look like this:
So, my input has the dimension (None, 540, 360, 3), output has dimensions (None, 540, 360) but if I add an internal array I can change the shape to (None, 540, 360, 1)
How would I define a CNN model such that my model could fit this criteria? How can I design a CNN with these inputs and outputs?
You have do differentiate between object detection and object segmentation. While both can be used for similar problems, the underlying CNN architectures look very different.
Object detection models use a CNN classification/regression architecure, where the output refers to the coordinates of the bounding boxes. It's common practice to use 4 values belonging to vertical center, horizontal center, width and height of each bounding box. Search for Faster R-CNN, SSD or YOLO to find popular object detection models for keras. In your case you would need to define a function that converts the current labels to the 4 coordinates I mentioned.
Object segmentation models commonly use an architecture referred to as encoder-decoder networks, where the original image is scaled down and compressed on the first half and then brought back to it's original resolution to predict a full image. Search for SegNet, U-Net or Tiramisu to find popular object segmentation models for keras. My own implementation of U-Net can be found here. In your case you would need to define a custom function, that fills all the 0s inside your bounding boxes with 1s. Understand that this solution will not predict bounding boxes as such, but segmentation maps showing regions of interest.
What is right for you, depends on what precisely you want to achieve. For getting actual bounding boxes you want to perform an object detection. However, if you're interested in highlighting regions of interest that go beyond rectangle windows a segmentation may be a better fit. In theory, you can use your rectangle labels for a segmentation, where the network will learn to create better masks than the inaccurate segmentation of the ground truth, provided you have enough data.
This is a simple example of how to write intermediate layers to achieve the output. You can use this as a starter code.
def model_360x540(input_shape=(360, 540, 3),num_classes=1):
inputs = Input(shape=input_shape)
# 360x540x3
downblock0 = Conv2D(32, (3, 3), padding='same')(inputs)
# 360x540x32
downblock0 = BatchNormalization()(block0)
downblock0 = Activation('relu')(block0)
downblock0_pool = MaxPooling2D((2, 2), strides=(2, 2))(block0)
# 180x270x32
centerblock0 = Conv2D(1024, (3, 3), padding='same')(downblock0_pool)
#180x270x1024
centerblock0 = BatchNormalization()(center)
centerblock0 = Activation('relu')(center)
upblock0 = UpSampling2D((2, 2))(centerblock0)
# 180x270x32
upblock0 = concatenate([downblock0 , upblock0], axis=3)
upblock0 = Activation('relu')(upblock0)
upblock0 = Conv2D(32, (3, 3), padding='same')(upblock0)
# 360x540x32
upblock0 = BatchNormalization()(upblock0)
upblock0 = Activation('relu')(upblock0)
classify = Conv2D(num_classes, (1, 1), activation='sigmoid')(upblock0)
#360x540x1
model = Model(inputs=inputs, outputs=classify)
model.compile(optimizer=RMSprop(lr=0.001), loss=bce_dice_loss, metrics=[dice_coeff])
return model
The downblock represents the block of layers which perform downsampling(MaxPooling2D).
The centerblock has no sampling layer.
The upblock represents the block of layers which perform up sampling(UpSampling2D).
So here you can see how (360,540,3) is being transformed to (360,540,1)
Basically, you can add such blocks of layers to create your model.
Also check out Holistically-Nested Edge Detection which will help you better with the edge detection task.
Hope this helps!
I have not worked with keras but I will provide a solution approach in more generalized way which can be used on any framework.
Here is full procedure.
Data preparation: I know your labels are edges of boxes which will also work but i will recommend that instead of edges you prepare dataset marking complete box like given in sample (I have marked for two boxes). Now your dataset have three classes (Box,Edges of box and background). Create two lists, Image and label.
Get a pre-trained model (RESNET-51 recommended) solver and train prototxt from here, Remove fc1000 layer and add de-convolution/up-sampling layers to match your input size. use paddding in first layer to make it square and crop in deconvolution layer to match input output dimensions.
Transfer weights from previously trained network (Original) and train your network.
Test your dataset and create bounding boxes using detected blobs.

How could I create a Gantt-like chart in a datawindow (Powerbuilder)

I want a rather simple (and cheap) solution, just for presentation purposes (and just to show the task duration bars - no connection lines between them). So, I am not interested in buying some advanced custom control like this for example. Have any of you ever used something like this? Are there any code samples available?
I would have pointed to Buck Woolley's dwExtreme site for an example of how to do a gantt in native DataWindow. However, "simple" I don't think is in your future if you want to roll your own. In fact, I'll be pleasantly surprised if someone writes a posting that includes a full description; I think it would take pages. (I'd be happy if someone proved me wrong.) In the meantime, here are some DataWindow basics I think you would need:
You can create an external DataWindow whose data source is not tied to a table
Columns in the data set do not have to be shown on the user interface
Columns in the data set can be used in expressions to evaluate attributes, so you could have a column for each of the following attributes of a rectangle:
x
width
color
I'd expect this to be a lot of work and time, and very likely to be worth the purchase the component (unless your time is valued at next to nothing, which in some IT shops is close to true).
Good luck,
Terry
(source: illudium.com)
You can make a simple Gantt chart with a Stacked Bar Graph (BarStacked (5) in the painter). The trick is to create a dummy series to space the bar out where you want it and make the dummy bar the same color as the graph's background (BackColor). It turns out you also need another dummy series with a small value to sit on the axis. Otherwise when you change the color of the bar that's doing the spacing, the axis line gets cut off. I found that .04 works well for this value.
Create the DataWindow
(This assumes familarity with the DataWindow Wizard. Refer to the PowerBuilder User's Guide for more information on creating graphs in DataWindows)
Click the icon for the new object wizard. Create a Graph DataWindow with an External data source. Create columns task type string(20), ser type string(1), and days type number. Set the Category to the task column and the Values to the days column. Click the Series button and select ser for the series. Don't bother with the title, and select the Stacked Bar graph type. When the painter opens, save the DataWindow. On the General tab in the Painter, change the Legend to None (0). On the Axis tab, select the Category axis, then set the sort to Unsorted (0). Select the Value axis then set the sort to Unsorted (0). Select the Series axis and set the sort to Ascending (1). Save the DataWindow.
Create the Window
Create a window and place a DataWindow control, dw_1. Set the data object to your graph DataWindow. Place the following in the open event (or pfc_postopen if using PFC).
try
dw_1.setRedraw(FALSE)
// LOAD DATA HERE
dw_1.object.gr_1.title = 'Project PBL Pusher'
dw_1.object.gr_1.category.label = 'Phase'
dw_1.object.gr_1.values.label = 'Project-Days'
catch (runtimeerror re)
if isvalid(gnv_app.inv_debug) then gnv_app.inv_debug.of_message(re.text) // could do better
finally
dw_1.setRedraw(TRUE)
end try
You would load the data for your chart where the comment says // LOAD DATA HERE
Script the graphcreate Event
Add an new event to dw_1. Select pbm_dwngraphcreate for the Event ID. I like to name these events by removing the pbm_dwn prefix so I use graphcreate. Add the following code to the event.
string ls_series
long li_color
try
li_color=long(dw_1.object.gr_1.backcolor)
// note first series is a dummy with a small value (0.04 seems to work) to keep the line from being hidden
ls_series = dw_1.seriesName("gr_1", 2)
if 0 = len(ls_series) then return // maybe show error message
// will return -1 when you set color same as the graph's backcolor but it sets the color
dw_1.setSeriesStyle("gr_1", ls_series, BackGround!, li_color) // the box
dw_1.setSeriesStyle("gr_1", ls_series, ForeGround!, li_color) // the inside
catch (runtimeerror re)
if isvalid(gnv_app.inv_debug) then gnv_app.inv_debug.of_message(re.text) // could do better
end try
Data for the Graph
Load the data with the categories in the reverse order of what you want. For each Task, insert 3 rows and set the series to a, b, and c, respectively. For series a in each task, set a small value. I used 0.04. You may have to experiment. For series b in each task, set the number of days before start. For series c, set the number of days. Below is the data in the sample DataWindow.
Task Ser Days
---- --- ----
Test a 0.04
Test b 24
Test c 10
Develop a 0.04
Develop b 10
Develop c 14
Design a 0.04
Design b 0
Design c 10
Sample DataWindow
Below is the source for a sample DataWindow in export format. You should be able to import into any version >= PB 10. Copy the code and paste it into a file with an SRD extension, then import it.
HA$PBExportHeader$d_graph.srd
release 10;
datawindow(units=0 timer_interval=0 color=1073741824 processing=3 HTMLDW=no print.printername="" print.documentname="" print.orientation = 1 print.margin.left = 110 print.margin.right = 110 print.margin.top = 96 print.margin.bottom = 96 print.paper.source = 0 print.paper.size = 0 print.canusedefaultprinter=yes print.prompt=no print.buttons=no print.preview.buttons=no print.cliptext=no print.overrideprintjob=no print.collate=yes hidegrayline=no )
summary(height=0 color="536870912" )
footer(height=0 color="536870912" )
detail(height=0 color="536870912" )
table(column=(type=char(10) updatewhereclause=yes name=task dbname="task" )
column=(type=char(1) updatewhereclause=yes name=ser dbname="ser" )
column=(type=number updatewhereclause=yes name=days dbname="days" )
)
data("Test","a", 0.04,"Test","b", 24,"Test","c", 10,"Develop","a", 0.04,"Develop","b", 10,"Develop","c", 14,"Design","a", 0.04,"Design","b", 0,"Design","c", 10,)
graph(band=background height="1232" width="2798" graphtype="5" perspective="2" rotation="-20" color="0" backcolor="16777215" shadecolor="8355711" range= 0 border="3" overlappercent="0" spacing="100" plotnulldata="0" elevation="20" depth="100"x="0" y="0" height="1232" width="2798" name=gr_1 visible="1" sizetodisplay=1 series="ser" category="task" values="days" title="Title" title.dispattr.backcolor="553648127" title.dispattr.alignment="2" title.dispattr.autosize="1" title.dispattr.font.charset="0" title.dispattr.font.escapement="0" title.dispattr.font.face="Tahoma" title.dispattr.font.family="2" title.dispattr.font.height="0" title.dispattr.font.italic="0" title.dispattr.font.orientation="0" title.dispattr.font.pitch="2" title.dispattr.font.strikethrough="0" title.dispattr.font.underline="0" title.dispattr.font.weight="700" title.dispattr.format="[general]" title.dispattr.textcolor="0" title.dispattr.displayexpression="title" legend="0" legend.dispattr.backcolor="536870912" legend.dispattr.alignment="0" legend.dispattr.autosize="1" legend.dispattr.font.charset="0" legend.dispattr.font.escapement="0" legend.dispattr.font.face="Tahoma" legend.dispattr.font.family="2" legend.dispattr.font.height="0" legend.dispattr.font.italic="0" legend.dispattr.font.orientation="0" legend.dispattr.font.pitch="2" legend.dispattr.font.strikethrough="0" legend.dispattr.font.underline="0" legend.dispattr.font.weight="400" legend.dispattr.format="[general]" legend.dispattr.textcolor="553648127" legend.dispattr.displayexpression="' '"
series.autoscale="1"
series.displayeverynlabels="0" series.droplines="0" series.frame="1" series.label="(None)" series.majordivisions="0" series.majorgridline="0" series.majortic="3" series.maximumvalue="0" series.minimumvalue="0" series.minordivisions="0" series.minorgridline="0" series.minortic="1" series.originline="1" series.primaryline="1" series.roundto="0" series.roundtounit="0" series.scaletype="1" series.scalevalue="1" series.secondaryline="0" series.shadebackedge="0" series.dispattr.backcolor="536870912" series.dispattr.alignment="0" series.dispattr.autosize="1" series.dispattr.font.charset="0" series.dispattr.font.escapement="0" series.dispattr.font.face="Tahoma" series.dispattr.font.family="2" series.dispattr.font.height="0" series.dispattr.font.italic="0" series.dispattr.font.orientation="0" series.dispattr.font.pitch="2" series.dispattr.font.strikethrough="0" series.dispattr.font.underline="0" series.dispattr.font.weight="400" series.dispattr.format="[general]" series.dispattr.textcolor="0" series.dispattr.displayexpression="series" series.labeldispattr.backcolor="553648127" series.labeldispattr.alignment="2" series.labeldispattr.autosize="1" series.labeldispattr.font.charset="0" series.labeldispattr.font.escapement="0" series.labeldispattr.font.face="Tahoma" series.labeldispattr.font.family="2" series.labeldispattr.font.height="0" series.labeldispattr.font.italic="0" series.labeldispattr.font.orientation="0" series.labeldispattr.font.pitch="2" series.labeldispattr.font.strikethrough="0" series.labeldispattr.font.underline="0" series.labeldispattr.font.weight="400" series.labeldispattr.format="[general]" series.labeldispattr.textcolor="0" series.labeldispattr.displayexpression=" seriesaxislabel" series.sort="1"
category.autoscale="1"
category.displayeverynlabels="0" category.droplines="0" category.frame="1" category.label="(None)" category.majordivisions="0" category.majorgridline="0" category.majortic="3" category.maximumvalue="0" category.minimumvalue="0" category.minordivisions="0" category.minorgridline="0" category.minortic="1" category.originline="0" category.primaryline="1" category.roundto="0" category.roundtounit="0" category.scaletype="1" category.scalevalue="1" category.secondaryline="0" category.shadebackedge="1" category.dispattr.backcolor="556870912" category.dispattr.alignment="1" category.dispattr.autosize="1" category.dispattr.font.charset="0" category.dispattr.font.escapement="0" category.dispattr.font.face="Tahoma" category.dispattr.font.family="2" category.dispattr.font.height="0" category.dispattr.font.italic="0" category.dispattr.font.orientation="0" category.dispattr.font.pitch="2" category.dispattr.font.strikethrough="0" category.dispattr.font.underline="0" category.dispattr.font.weight="400" category.dispattr.format="[general]" category.dispattr.textcolor="0" category.dispattr.displayexpression="category" category.labeldispattr.backcolor="556870912" category.labeldispattr.alignment="2" category.labeldispattr.autosize="1" category.labeldispattr.font.charset="0" category.labeldispattr.font.escapement="900" category.labeldispattr.font.face="Tahoma" category.labeldispattr.font.family="2" category.labeldispattr.font.height="0" category.labeldispattr.font.italic="0" category.labeldispattr.font.orientation="900" category.labeldispattr.font.pitch="2" category.labeldispattr.font.strikethrough="0" category.labeldispattr.font.underline="0" category.labeldispattr.font.weight="400" category.labeldispattr.format="[general]" category.labeldispattr.textcolor="0" category.labeldispattr.displayexpression="categoryaxislabel" category.sort="0"
values.autoscale="1"
values.displayeverynlabels="0" values.droplines="0" values.frame="1" values.label="(None)" values.majordivisions="0" values.majorgridline="0" values.majortic="3" values.maximumvalue="1500" values.minimumvalue="0" values.minordivisions="0" values.minorgridline="0" values.minortic="1" values.originline="1" values.primaryline="1" values.roundto="0" values.roundtounit="0" values.scaletype="1" values.scalevalue="1" values.secondaryline="0" values.shadebackedge="0" values.dispattr.backcolor="556870912" values.dispattr.alignment="2" values.dispattr.autosize="1" values.dispattr.font.charset="0" values.dispattr.font.escapement="0" values.dispattr.font.face="Tahoma" values.dispattr.font.family="2" values.dispattr.font.height="0" values.dispattr.font.italic="0" values.dispattr.font.orientation="0" values.dispattr.font.pitch="2" values.dispattr.font.strikethrough="0" values.dispattr.font.underline="0" values.dispattr.font.weight="400" values.dispattr.format="[General]" values.dispattr.textcolor="0" values.dispattr.displayexpression="value" values.labeldispattr.backcolor="553648127" values.labeldispattr.alignment="2" values.labeldispattr.autosize="1" values.labeldispattr.font.charset="0" values.labeldispattr.font.escapement="0" values.labeldispattr.font.face="Tahoma" values.labeldispattr.font.family="2" values.labeldispattr.font.height="0" values.labeldispattr.font.italic="0" values.labeldispattr.font.orientation="0" values.labeldispattr.font.pitch="2" values.labeldispattr.font.strikethrough="0" values.labeldispattr.font.underline="0" values.labeldispattr.font.weight="700" values.labeldispattr.format="[general]" values.labeldispattr.textcolor="0" values.labeldispattr.displayexpression="valuesaxislabel" )
htmltable(border="1" )
htmlgen(clientevents="1" clientvalidation="1" clientcomputedfields="1" clientformatting="0" clientscriptable="0" generatejavascript="1" encodeselflinkargs="1" netscapelayers="0" )
xhtmlgen() cssgen(sessionspecific="0" )
xmlgen(inline="0" )
xsltgen()
jsgen()
export.xml(headgroups="1" includewhitespace="0" metadatatype=0 savemetadata=0 )
import.xml()
export.pdf(method=0 distill.custompostscript="0" xslfop.print="0" )
export.xhtml()

WPF 3d ImageBrush material help

Im trying to apply a material to my GeometryModel3D at runtime like so:
var model3D = ShardModelVisual.Content as GeometryModel3D;
var materialGroup = model3D.Material as MaterialGroup;
BitmapImage image;
ResourceLoader.TryLoadImage("pack://application:,,,/AnzSurface;component/path file/img.png", out image, ".png");
var iceBrush = new ImageBrush(image);
var grp = new TransformGroup();
grp.Children.Add(new ScaleTransform(0.25, 0.65, 0.5, 0.5));
grp.Children.Add(new TranslateTransform(0.0, 0.0));
iceBrush.Transform = grp;
var iceMat = new DiffuseMaterial(iceBrush);
materialGroup.Children.Add(iceMat);
Which all works fine, and the material gets added.
What I dont understand is how I can map the users click on the screen to the offsets that need to be applied to the TranslateTransform.
I.e. at the moment, x: -0.25 moves the material backwards along the X axis, but I have NO IDEA how to get that type of a coordinate from the users mouse click...
when I do:
e.MouseDevice.GetPosition(ShardsViewPort3D);
that gives me normal X/Y corrds of the mouse click...
Thanks for any help you can give!
It sounds like you want to slide the material around on your geometry when you click on it. Here's how:
Use hit testing to translate your X/Y coordinates from the mouse click into a RayMeshGeometry3DHitTestResult as described in my earlier answer. This will give you the MeshGeometry3D that was hit, the vertices of the triangle that was hit, and the relative position on that triangle.
Look up each vertex index (VertexIndex1, VertexIndex2, VertexIndex2) in the MeshGeometry3D.TextureCoordinates to get the texture coordinates. This will give you three (u,v) pairs as Point objects. Multiply each the (u,v) pairs by the corresponding weight from the hit test result (VertexWeight1, VertexWeight2, VertexWeight3) and add the pairs together, ie:
uMouse = u1 * VertexWeight1 + u2 * VertexWeight2 + u3 * VertexWeight3
vMouse = v1 * VertexWeight1 + v2 * VertexWeight2 + v3 * VertexWeight3
Now you have a point (uMouse, vMouse) that indicates where on your material your mouse was clicked.
If you want a particular point on your texture to move to exactly where the mouse was clicked, just subtract the (uMouse, vMouse) where the mouse was clicked from the (u,v) coordinate of the location in the material you want to appear under the mouse, and set this as your TranslateTransform. If you want to handle dragging, store the computed (uMouse,vMouse) where the drag started and the transform as of the drag start, then as dragging progresses compute the new transform as:
translate = (uMouse,vMouse) - (uMouseDragStart, vMouseDragStart) + origTranslate
In code you'll write this as Point additions. I spelled it out as (u,v) in this explanation because I thought it was easier to understand if I did so. In actuality the code to compute (uMouse, vMouse) will look more like this:
var uv1 = hit.MeshHit.TextureCoordinates[hit.VertexIndex1];
var uv2 = hit.MeshHit.TextureCoordinates[hit.VertexIndex2];
var uv3 = hit.MeshHit.TextureCoordinates[hit.VertexIndex3];
var uvMouse = new Vector(
uv1.X * hit.VertexWeight1 + uv2.X * hit.VertexWeight2 + uv3.X * hit.VertexWeight3)
uv1.Y * hit.VertexWeight1 + uv2.Y * hit.VertexWeight2 + uv3.Y * hit.VertexWeight3);
and the code to update the transform during a drag will look something like this:
...
var translate = translateAtDragStart + uvMouse - uvMouseAtDragStart;
... = new TranslateTransform(translate.X, translate.Y);
You'll have to adapt this to the exact situation.
Note that your HitTest callback may be called multiple times, starting at the closest mesh and moving back. It may even be called with 2D hits, for example if a 2D object is in front of your Viewport3D. So you'll want to check each hit to see if it is really what you want, for example during dragging you want to keep checking the position on the mesh being dragged even if it is no longer foremost. Return HitTestResultBehavior.Stop from you callback once you have acted on the mesh being dragged.

Resources